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