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 tftp_file_read_undi(const char *name,
39 int (*fnc)(unsigned char *, unsigned int, unsigned int, int));
40 static int tftp_read_undi(char *addr, int size);
41 static int tftp_dir_undi(char *dirname);
42 static void tftp_close_undi(void);
43 static int buf_fill_undi(int abort);
44
45 extern int use_bios_pxe;
46
47 static int retry;
48 static unsigned short iport = 2000;
49 static unsigned short oport = 0;
50 static unsigned short block, prevblock;
51 static int bcounter;
52 static struct tftp_t tp, saved_tp;
53 static int packetsize;
54 static int buf_eof, buf_read;
55 static int saved_filepos;
56 static unsigned short len, saved_len;
57 static char *buf, *saved_name;
58
59 /**
60 * tftp_read
61 *
62 * Read file with _name_, data handled by _fnc_. In fact, grub never
63 * use it, we just use it to read dhcp config file.
64 */
await_tftp(int ival,void * ptr __unused,unsigned short ptype __unused,struct iphdr * ip,struct udphdr * udp)65 static int await_tftp(int ival, void *ptr __unused,
66 unsigned short ptype __unused, struct iphdr *ip,
67 struct udphdr *udp)
68 {
69 static int tftp_count = 0;
70
71 if (!udp) {
72 return 0;
73 }
74 if (arptable[ARP_CLIENT].ipaddr.s_addr != ip->dest.s_addr)
75 return 0;
76 if (ntohs(udp->dest) != ival)
77 return 0;
78 tftp_count++; /* show progress */
79 if ((tftp_count % 1000) == 0)
80 printf(".");
81 return 1;
82 }
83
tftp_file_read(const char * name,int (* fnc)(unsigned char *,unsigned int,unsigned int,int))84 int tftp_file_read(const char *name, int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
85 {
86 struct tftpreq_t tp;
87 struct tftp_t *tr;
88 int rc;
89
90 if (use_bios_pxe)
91 return (tftp_file_read_undi(name, fnc));
92
93 retry = 0;
94 block = 0;
95 prevblock = 0;
96 bcounter = 0;
97
98
99 rx_qdrain();
100
101 tp.opcode = htons(TFTP_RRQ);
102 /* Warning: the following assumes the layout of bootp_t.
103 But that's fixed by the IP, UDP and BOOTP specs. */
104 len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) +
105 sprintf((char *)tp.u.rrq, "%s%coctet%cblksize%c%d",
106 name, 0, 0, 0, TFTP_MAX_PACKET) + 1;
107 if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
108 TFTP_PORT, len, &tp))
109 return (0);
110 for (;;)
111 {
112 long timeout;
113 #ifdef CONGESTED
114 timeout = rfc2131_sleep_interval(block?TFTP_REXMT: TIMEOUT, retry);
115 #else
116 timeout = rfc2131_sleep_interval(TIMEOUT, retry);
117 #endif
118 if (!await_reply(await_tftp, iport, NULL, timeout))
119 {
120 if (!block && retry++ < MAX_TFTP_RETRIES)
121 { /* maybe initial request was lost */
122 if (!udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
123 ++iport, TFTP_PORT, len, &tp))
124 return (0);
125 continue;
126 }
127 #ifdef CONGESTED
128 if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
129 { /* we resend our last ack */
130 #ifdef MDEBUG
131 printf("<REXMT>\n");
132 #endif
133 udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
134 iport, oport,
135 TFTP_MIN_PACKET, &tp);
136 continue;
137 }
138 #endif
139 break; /* timeout */
140 }
141 tr = (struct tftp_t *)&nic.packet[ETH_HLEN];
142 if (tr->opcode == ntohs(TFTP_ERROR))
143 {
144 printf("TFTP error %d (%s)\n",
145 ntohs(tr->u.err.errcode),
146 tr->u.err.errmsg);
147 break;
148 }
149
150 if (tr->opcode == ntohs(TFTP_OACK)) {
151 char *p = tr->u.oack.data, *e;
152
153 if (prevblock) /* shouldn't happen */
154 continue; /* ignore it */
155 len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 2;
156 if (len > TFTP_MAX_PACKET)
157 goto noak;
158 e = p + len;
159 while (*p != '\0' && p < e) {
160 /* if (!strcasecmp("blksize", p)) { */
161 if (!grub_strcmp("blksize", p)) {
162 p += 8;
163 /* if ((packetsize = strtoul(p, &p, 10)) < */
164 if ((packetsize = getdec(&p)) < TFTP_DEFAULTSIZE_PACKET)
165 goto noak;
166 while (p < e && *p) p++;
167 if (p < e)
168 p++;
169 }
170 else {
171 noak:
172 tp.opcode = htons(TFTP_ERROR);
173 tp.u.err.errcode = 8;
174 /*
175 * Warning: the following assumes the layout of bootp_t.
176 * But that's fixed by the IP, UDP and BOOTP specs.
177 */
178 len = sizeof(tp.ip) + sizeof(tp.udp) + sizeof(tp.opcode) + sizeof(tp.u.err.errcode) +
179 /*
180 * Normally bad form to omit the format string, but in this case
181 * the string we are copying from is fixed. sprintf is just being
182 * used as a strcpy and strlen.
183 */
184 sprintf((char *)tp.u.err.errmsg,
185 "RFC1782 error") + 1;
186 udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr,
187 iport, ntohs(tr->udp.src),
188 len, &tp);
189 return (0);
190 }
191 }
192 if (p > e)
193 goto noak;
194 block = tp.u.ack.block = 0; /* this ensures, that */
195 /* the packet does not get */
196 /* processed as data! */
197 }
198 else if (tr->opcode == htons(TFTP_DATA)) {
199 len = ntohs(tr->udp.len) - sizeof(struct udphdr) - 4;
200 if (len > packetsize) /* shouldn't happen */
201 continue; /* ignore it */
202 block = ntohs(tp.u.ack.block = tr->u.data.block); }
203 else {/* neither TFTP_OACK nor TFTP_DATA */
204 break;
205 }
206
207 if ((block || bcounter) && (block != (unsigned short)(prevblock+1))) {
208 /* Block order should be continuous */
209 tp.u.ack.block = htons(block = prevblock);
210 }
211 tp.opcode = htons(TFTP_ACK);
212 oport = ntohs(tr->udp.src);
213 udp_transmit(arptable[ARP_SERVER].ipaddr.s_addr, iport,
214 oport, TFTP_MIN_PACKET, &tp); /* ack */
215 if ((unsigned short)(block-prevblock) != 1) {
216 /* Retransmission or OACK, don't process via callback
217 * and don't change the value of prevblock. */
218 continue;
219 }
220 prevblock = block;
221 retry = 0; /* It's the right place to zero the timer? */
222 if ((rc = fnc(tr->u.data.download,
223 ++bcounter, len, len < packetsize)) <= 0)
224 return(rc);
225 if (len < packetsize) { /* End of data --- fnc should not have returned */
226 printf("tftp download complete, but\n");
227 return (1);
228 }
229 }
230 return (0);
231 }
232
233 /* Fill the buffer by receiving the data via the TFTP protocol. */
234 static int
buf_fill(int abort)235 buf_fill (int abort)
236 {
237 #ifdef TFTP_DEBUG
238 grub_printf ("buf_fill (%d)\n", abort);
239 #endif
240
241 if (use_bios_pxe)
242 return (buf_fill_undi(abort));
243
244 while (! buf_eof && (buf_read + packetsize <= FSYS_BUFLEN))
245 {
246 struct tftp_t *tr;
247 long timeout;
248
249 #ifdef CONGESTED
250 timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry);
251 #else
252 timeout = rfc2131_sleep_interval (TIMEOUT, retry);
253 #endif
254
255 if (! await_reply (await_tftp, iport, NULL, timeout))
256 {
257 if (user_abort)
258 return 0;
259
260 if (! block && retry++ < MAX_TFTP_RETRIES)
261 {
262 /* Maybe initial request was lost. */
263 #ifdef TFTP_DEBUG
264 grub_printf ("Maybe initial request was lost.\n");
265 #endif
266 if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
267 ++iport, TFTP_PORT, len, &tp))
268 return 0;
269
270 continue;
271 }
272
273 #ifdef CONGESTED
274 if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
275 {
276 /* We resend our last ack. */
277 # ifdef TFTP_DEBUG
278 grub_printf ("<REXMT>\n");
279 # endif
280 udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
281 iport, oport,
282 TFTP_MIN_PACKET, &tp);
283 continue;
284 }
285 #endif
286 /* Timeout. */
287 return 0;
288 }
289
290 tr = (struct tftp_t *) &nic.packet[ETH_HLEN];
291 if (tr->opcode == ntohs (TFTP_ERROR))
292 {
293 grub_printf ("TFTP error %d (%s)\n",
294 ntohs (tr->u.err.errcode),
295 tr->u.err.errmsg);
296 return 0;
297 }
298
299 if (tr->opcode == ntohs (TFTP_OACK))
300 {
301 char *p = tr->u.oack.data, *e;
302
303 #ifdef TFTP_DEBUG
304 grub_printf ("OACK ");
305 #endif
306 /* Shouldn't happen. */
307 if (prevblock)
308 {
309 /* Ignore it. */
310 grub_printf ("%s:%d: warning: PREVBLOCK != 0 (0x%x)\n",
311 __FILE__, __LINE__, prevblock);
312 continue;
313 }
314
315 len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2;
316 if (len > TFTP_MAX_PACKET)
317 goto noak;
318
319 e = p + len;
320 while (*p != '\000' && p < e)
321 {
322 if (! grub_strcmp ("blksize", p))
323 {
324 p += 8;
325 if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET)
326 goto noak;
327 #ifdef TFTP_DEBUG
328 grub_printf ("blksize = %d\n", packetsize);
329 #endif
330 }
331 else if (! grub_strcmp ("tsize", p))
332 {
333 p += 6;
334 if ((filemax = getdec (&p)) < 0)
335 {
336 filemax = -1;
337 goto noak;
338 }
339 #ifdef TFTP_DEBUG
340 grub_printf ("tsize = %d\n", filemax);
341 #endif
342 }
343 else
344 {
345 noak:
346 #ifdef TFTP_DEBUG
347 grub_printf ("NOAK\n");
348 #endif
349 tp.opcode = htons (TFTP_ERROR);
350 tp.u.err.errcode = 8;
351 len = (grub_sprintf ((char *) tp.u.err.errmsg,
352 "RFC1782 error")
353 + sizeof (tp.ip) + sizeof (tp.udp)
354 + sizeof (tp.opcode) + sizeof (tp.u.err.errcode)
355 + 1);
356 udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
357 iport, ntohs (tr->udp.src),
358 len, &tp);
359 return 0;
360 }
361
362 while (p < e && *p)
363 p++;
364
365 if (p < e)
366 p++;
367 }
368
369 if (p > e)
370 goto noak;
371
372 /* This ensures that the packet does not get processed as
373 data! */
374 block = tp.u.ack.block = 0;
375 }
376 else if (tr->opcode == ntohs (TFTP_DATA))
377 {
378 #ifdef TFTP_DEBUG
379 grub_printf ("DATA ");
380 #endif
381 len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4;
382
383 /* Shouldn't happen. */
384 if (len > packetsize)
385 {
386 /* Ignore it. */
387 grub_printf ("%s:%d: warning: LEN > PACKETSIZE (0x%x > 0x%x)\n",
388 __FILE__, __LINE__, len, packetsize);
389 continue;
390 }
391
392 block = ntohs (tp.u.ack.block = tr->u.data.block);
393 }
394 else
395 /* Neither TFTP_OACK nor TFTP_DATA. */
396 break;
397
398 if ((block || bcounter) && (block != (unsigned short) (prevblock + 1)))
399 /* Block order should be continuous */
400 tp.u.ack.block = htons (block = prevblock);
401
402 /* Should be continuous. */
403 tp.opcode = abort ? htons (TFTP_ERROR) : htons (TFTP_ACK);
404 oport = ntohs (tr->udp.src);
405
406 #ifdef TFTP_DEBUG
407 grub_printf ("ACK\n");
408 #endif
409 /* Ack. */
410 udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport,
411 oport, TFTP_MIN_PACKET, &tp);
412
413 if (abort)
414 {
415 buf_eof = 1;
416 break;
417 }
418
419 /* Retransmission or OACK. */
420 if ((unsigned short) (block - prevblock) != 1)
421 /* Don't process. */
422 continue;
423
424 prevblock = block;
425 /* Is it the right place to zero the timer? */
426 retry = 0;
427
428 /* In GRUB, this variable doesn't play any important role at all,
429 but use it for consistency with Etherboot. */
430 bcounter++;
431
432 /* Copy the downloaded data to the buffer. */
433 grub_memmove (buf + buf_read, tr->u.data.download, len);
434 buf_read += len;
435
436 /* End of data. */
437 if (len < packetsize)
438 buf_eof = 1;
439 }
440
441 return 1;
442 }
443
444 /* Send the RRQ whose length is LEN. */
445 static int
send_rrq(void)446 send_rrq (void)
447 {
448 /* Initialize some variables. */
449 retry = 0;
450 block = 0;
451 prevblock = 0;
452 packetsize = TFTP_DEFAULTSIZE_PACKET;
453 bcounter = 0;
454
455 buf = (char *) FSYS_BUF;
456 buf_eof = 0;
457 buf_read = 0;
458 saved_filepos = 0;
459
460 rx_qdrain();
461
462 #ifdef TFTP_DEBUG
463 grub_printf ("send_rrq ()\n");
464 {
465 int i;
466 char *p;
467
468 for (i = 0, p = (char *) &tp; i < len; i++)
469 if (p[i] >= ' ' && p[i] <= '~')
470 grub_putchar (p[i]);
471 else
472 grub_printf ("\\%x", (unsigned) p[i]);
473
474 grub_putchar ('\n');
475 }
476 #endif
477 /* Send the packet. */
478 return udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
479 TFTP_PORT, len, &tp);
480 }
481
482 /* Mount the network drive. If the drive is ready, return one, otherwise
483 return zero. */
484 int
tftp_mount(void)485 tftp_mount (void)
486 {
487 /* Check if the current drive is the network drive. */
488 if (current_drive != NETWORK_DRIVE)
489 return 0;
490
491 /* If the drive is not initialized yet, abort. */
492 if (! network_ready)
493 return 0;
494
495 return 1;
496 }
497
498 /* Read up to SIZE bytes, returned in ADDR. */
499 int
tftp_read(char * addr,int size)500 tftp_read (char *addr, int size)
501 {
502 /* How many bytes is read? */
503 int ret = 0;
504
505 #ifdef TFTP_DEBUG
506 grub_printf ("tftp_read (0x%x, %d)\n", (int) addr, size);
507 #endif
508
509 if (use_bios_pxe)
510 return (tftp_read_undi(addr, size));
511
512 if (filepos < saved_filepos)
513 {
514 /* Uggh.. FILEPOS has been moved backwards. So reopen the file. */
515 buf_read = 0;
516 buf_fill (1);
517 grub_memmove ((char *) &tp, (char *) &saved_tp, saved_len);
518 len = saved_len;
519 #ifdef TFTP_DEBUG
520 {
521 int i;
522 grub_printf ("opcode = 0x%x, rrq = ", (unsigned long) tp.opcode);
523 for (i = 0; i < TFTP_DEFAULTSIZE_PACKET; i++)
524 {
525 if (tp.u.rrq[i] >= ' ' && tp.u.rrq[i] <= '~')
526 grub_putchar (tp.u.rrq[i]);
527 else
528 grub_putchar ('*');
529 }
530 grub_putchar ('\n');
531 }
532 #endif
533
534 if (! send_rrq ())
535 {
536 errnum = ERR_WRITE;
537 return 0;
538 }
539 }
540
541 while (size > 0)
542 {
543 int amt = buf_read + saved_filepos - filepos;
544
545 /* If the length that can be copied from the buffer is over the
546 requested size, cut it down. */
547 if (amt > size)
548 amt = size;
549
550 if (amt > 0)
551 {
552 /* Copy the buffer to the supplied memory space. */
553 grub_memmove (addr, buf + filepos - saved_filepos, amt);
554 size -= amt;
555 addr += amt;
556 filepos += amt;
557 ret += amt;
558
559 /* If the size of the empty space becomes small, move the unused
560 data forwards. */
561 if (filepos - saved_filepos > FSYS_BUFLEN / 2)
562 {
563 grub_memmove (buf, buf + FSYS_BUFLEN / 2, FSYS_BUFLEN / 2);
564 buf_read -= FSYS_BUFLEN / 2;
565 saved_filepos += FSYS_BUFLEN / 2;
566 }
567 }
568 else
569 {
570 /* Skip the whole buffer. */
571 saved_filepos += buf_read;
572 buf_read = 0;
573 }
574
575 /* Read the data. */
576 if (size > 0 && ! buf_fill (0))
577 {
578 errnum = ERR_READ;
579 return 0;
580 }
581
582 /* Sanity check. */
583 if (size > 0 && buf_read == 0)
584 {
585 errnum = ERR_READ;
586 return 0;
587 }
588 }
589
590 return ret;
591 }
592
593 /* Check if the file DIRNAME really exists. Get the size and save it in
594 FILEMAX. */
595 int
tftp_dir(char * dirname)596 tftp_dir (char *dirname)
597 {
598 int ch;
599
600 #ifdef TFTP_DEBUG
601 grub_printf ("tftp_dir (%s)\n", dirname);
602 #endif
603
604 if (use_bios_pxe)
605 return (tftp_dir_undi(dirname));
606
607 /* In TFTP, there is no way to know what files exist. */
608 if (print_possibilities)
609 return 1;
610
611 /* Don't know the size yet. */
612 filemax = -1;
613
614 reopen:
615 /* Construct the TFTP request packet. */
616 tp.opcode = htons (TFTP_RRQ);
617 /* Terminate the filename. */
618 ch = nul_terminate (dirname);
619 /* Make the request string (octet, blksize and tsize). */
620 len = (grub_sprintf ((char *) tp.u.rrq,
621 "%s%coctet%cblksize%c%d%ctsize%c0",
622 dirname, 0, 0, 0, TFTP_MAX_PACKET, 0, 0)
623 + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1);
624 /* Restore the original DIRNAME. */
625 dirname[grub_strlen (dirname)] = ch;
626 /* Save the TFTP packet so that we can reopen the file later. */
627 grub_memmove ((char *) &saved_tp, (char *) &tp, len);
628 saved_len = len;
629 if (! send_rrq ())
630 {
631 errnum = ERR_WRITE;
632 return 0;
633 }
634
635 /* Read the data. */
636 if (! buf_fill (0))
637 {
638 errnum = ERR_FILE_NOT_FOUND;
639 return 0;
640 }
641
642 if (filemax == -1)
643 {
644 /* The server doesn't support the "tsize" option, so we must read
645 the file twice... */
646
647 /* Zero the size of the file. */
648 filemax = 0;
649 do
650 {
651 /* Add the length of the downloaded data. */
652 filemax += buf_read;
653 /* Reset the offset. Just discard the contents of the buffer. */
654 buf_read = 0;
655 /* Read the data. */
656 if (! buf_fill (0))
657 {
658 errnum = ERR_READ;
659 return 0;
660 }
661 }
662 while (! buf_eof);
663
664 /* Maybe a few amounts of data remains. */
665 filemax += buf_read;
666
667 /* Retry the open instruction. */
668 goto reopen;
669 }
670
671 return 1;
672 }
673
674 /* Close the file. */
675 void
tftp_close(void)676 tftp_close (void)
677 {
678 #ifdef TFTP_DEBUG
679 grub_printf ("tftp_close ()\n");
680 #endif
681
682 if (use_bios_pxe) {
683 tftp_close_undi();
684 return;
685 }
686
687 buf_read = 0;
688 buf_fill (1);
689 }
690
691 /* tftp implementation using BIOS established PXE stack */
692
tftp_file_read_undi(const char * name,int (* fnc)(unsigned char *,unsigned int,unsigned int,int))693 static int tftp_file_read_undi(const char *name,
694 int (*fnc)(unsigned char *, unsigned int, unsigned int, int))
695 {
696 int rc;
697 uint16_t len;
698
699 buf = (char *)&nic.packet;
700 /* open tftp session */
701 if (eb_pxenv_tftp_open(name, arptable[ARP_SERVER].ipaddr,
702 arptable[ARP_GATEWAY].ipaddr, &packetsize) == 0)
703 return (0);
704
705 /* read blocks and invoke fnc for each block */
706 for (;;) {
707 rc = eb_pxenv_tftp_read(buf, &len);
708 if (rc == 0)
709 break;
710 rc = fnc(buf, ++block, len, len < packetsize);
711 if (rc <= 0 || len < packetsize)
712 break;
713 }
714
715 (void) eb_pxenv_tftp_close();
716 return (rc > 0 ? 1 : 0);
717 }
718
719 /* Fill the buffer by reading the data via the TFTP protocol. */
720 static int
buf_fill_undi(int abort)721 buf_fill_undi(int abort)
722 {
723 int rc;
724 uint8_t *tmpbuf;
725
726 while (! buf_eof && (buf_read + packetsize <= FSYS_BUFLEN)) {
727 poll_interruptions();
728 if (user_abort)
729 return 0;
730 if (abort) {
731 buf_eof = 1;
732 break;
733 }
734
735 if (eb_pxenv_tftp_read(buf + buf_read, &len) == 0)
736 return (0);
737
738 buf_read += len;
739
740 /* End of data. */
741 if (len < packetsize)
742 buf_eof = 1;
743 }
744 return 1;
745 }
746
747 static void
tftp_reopen_undi(void)748 tftp_reopen_undi(void)
749 {
750 tftp_close();
751 (void) eb_pxenv_tftp_open(saved_name, arptable[ARP_SERVER].ipaddr,
752 arptable[ARP_GATEWAY].ipaddr, &packetsize);
753
754 buf_eof = 0;
755 buf_read = 0;
756 saved_filepos = 0;
757 }
758
759 /* Read up to SIZE bytes, returned in ADDR. */
760 static int
tftp_read_undi(char * addr,int size)761 tftp_read_undi(char *addr, int size)
762 {
763 int ret = 0;
764
765 if (filepos < saved_filepos) {
766 /* Uggh.. FILEPOS has been moved backwards. reopen the file. */
767 tftp_reopen_undi();
768 }
769
770 while (size > 0) {
771 int amt = buf_read + saved_filepos - filepos;
772
773 /* If the length that can be copied from the buffer is over
774 the requested size, cut it down. */
775 if (amt > size)
776 amt = size;
777
778 if (amt > 0) {
779 /* Copy the buffer to the supplied memory space. */
780 grub_memmove (addr, buf + filepos - saved_filepos, amt);
781 size -= amt;
782 addr += amt;
783 filepos += amt;
784 ret += amt;
785
786 /* If the size of the empty space becomes small,
787 * move the unused data forwards.
788 */
789 if (filepos - saved_filepos > FSYS_BUFLEN / 2) {
790 grub_memmove (buf, buf + FSYS_BUFLEN / 2,
791 FSYS_BUFLEN / 2);
792 buf_read -= FSYS_BUFLEN / 2;
793 saved_filepos += FSYS_BUFLEN / 2;
794 }
795 } else {
796 /* Skip the whole buffer. */
797 saved_filepos += buf_read;
798 buf_read = 0;
799 }
800
801 /* Read the data. */
802 if (size > 0 && ! buf_fill (0)) {
803 errnum = ERR_READ;
804 return 0;
805 }
806
807 /* Sanity check. */
808 if (size > 0 && buf_read == 0) {
809 errnum = ERR_READ;
810 return 0;
811 }
812 }
813
814 return ret;
815 }
816
817 static int
tftp_dir_undi(char * dirname)818 tftp_dir_undi(char *dirname)
819 {
820 int rc, ch;
821 uint16_t len;
822
823 /* In TFTP, there is no way to know what files exist. */
824 if (print_possibilities)
825 return 1;
826
827 /* name may be space terminated */
828 ch = nul_terminate(dirname);
829 saved_name = (char *)&saved_tp;
830 sprintf(saved_name, "%s", dirname);
831
832 /* Restore the original dirname */
833 dirname[grub_strlen (dirname)] = ch;
834
835 /* get the file size; must call before tftp_open */
836 rc = eb_pxenv_tftp_get_fsize(saved_name, arptable[ARP_SERVER].ipaddr,
837 arptable[ARP_GATEWAY].ipaddr, &filemax);
838
839 /* open tftp session */
840 if (eb_pxenv_tftp_open(saved_name, arptable[ARP_SERVER].ipaddr,
841 arptable[ARP_GATEWAY].ipaddr, &packetsize) == 0)
842 return (0);
843
844 buf = (char *) FSYS_BUF;
845 buf_eof = 0;
846 buf_read = 0;
847 saved_filepos = 0;
848
849 if (rc == 0) {
850 /* Read the entire file to get filemax */
851 filemax = 0;
852 do {
853 /* Add the length of the downloaded data. */
854 filemax += buf_read;
855 buf_read = 0;
856 if (! buf_fill (0)) {
857 errnum = ERR_READ;
858 return 0;
859 }
860 } while (! buf_eof);
861
862 /* Maybe a few amounts of data remains. */
863 filemax += buf_read;
864
865 tftp_reopen_undi(); /* reopen file to read from beginning */
866 }
867
868 return (1);
869 }
870
871 static void
tftp_close_undi(void)872 tftp_close_undi(void)
873 {
874 buf_read = 0;
875 buf_fill (1);
876 (void) eb_pxenv_tftp_close();
877 }
878