1 /* 2 * Based on LiMon - BOOTP. 3 * 4 * Copyright 1994, 1995, 2000 Neil Russell. 5 * (See License) 6 * Copyright 2000 Roland Borde 7 * Copyright 2000 Paolo Scaffardi 8 * Copyright 2000-2004 Wolfgang Denk, wd@denx.de 9 */ 10 11 #include <common.h> 12 #include <command.h> 13 #include <net.h> 14 #include "bootp.h" 15 #include "tftp.h" 16 #include "nfs.h" 17 #ifdef CONFIG_STATUS_LED 18 #include <status_led.h> 19 #endif 20 #ifdef CONFIG_BOOTP_RANDOM_DELAY 21 #include "net_rand.h" 22 #endif 23 24 #define BOOTP_VENDOR_MAGIC 0x63825363 /* RFC1048 Magic Cookie */ 25 26 /* 27 * The timeout for the initial BOOTP/DHCP request used to be described by a 28 * counter of fixed-length timeout periods. TIMEOUT_COUNT represents 29 * that counter 30 * 31 * Now that the timeout periods are variable (exponential backoff and retry) 32 * we convert the timeout count to the absolute time it would have take to 33 * execute that many retries, and keep sending retry packets until that time 34 * is reached. 35 */ 36 #ifndef CONFIG_NET_RETRY_COUNT 37 # define TIMEOUT_COUNT 5 /* # of timeouts before giving up */ 38 #else 39 # define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT) 40 #endif 41 #define TIMEOUT_MS ((3 + (TIMEOUT_COUNT * 5)) * 1000) 42 43 #define PORT_BOOTPS 67 /* BOOTP server UDP port */ 44 #define PORT_BOOTPC 68 /* BOOTP client UDP port */ 45 46 #ifndef CONFIG_DHCP_MIN_EXT_LEN /* minimal length of extension list */ 47 #define CONFIG_DHCP_MIN_EXT_LEN 64 48 #endif 49 50 ulong BootpID; 51 int BootpTry; 52 ulong bootp_start; 53 ulong bootp_timeout; 54 55 #if defined(CONFIG_CMD_DHCP) 56 static dhcp_state_t dhcp_state = INIT; 57 static unsigned long dhcp_leasetime; 58 static IPaddr_t NetDHCPServerIP; 59 static void DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, 60 unsigned len); 61 62 /* For Debug */ 63 #if 0 64 static char *dhcpmsg2str(int type) 65 { 66 switch (type) { 67 case 1: return "DHCPDISCOVER"; break; 68 case 2: return "DHCPOFFER"; break; 69 case 3: return "DHCPREQUEST"; break; 70 case 4: return "DHCPDECLINE"; break; 71 case 5: return "DHCPACK"; break; 72 case 6: return "DHCPNACK"; break; 73 case 7: return "DHCPRELEASE"; break; 74 default: return "UNKNOWN/INVALID MSG TYPE"; break; 75 } 76 } 77 #endif 78 #endif 79 80 static int BootpCheckPkt(uchar *pkt, unsigned dest, unsigned src, unsigned len) 81 { 82 struct Bootp_t *bp = (struct Bootp_t *) pkt; 83 int retval = 0; 84 85 if (dest != PORT_BOOTPC || src != PORT_BOOTPS) 86 retval = -1; 87 else if (len < sizeof(struct Bootp_t) - OPT_FIELD_SIZE) 88 retval = -2; 89 else if (bp->bp_op != OP_BOOTREQUEST && 90 bp->bp_op != OP_BOOTREPLY && 91 bp->bp_op != DHCP_OFFER && 92 bp->bp_op != DHCP_ACK && 93 bp->bp_op != DHCP_NAK) 94 retval = -3; 95 else if (bp->bp_htype != HWT_ETHER) 96 retval = -4; 97 else if (bp->bp_hlen != HWL_ETHER) 98 retval = -5; 99 else if (NetReadLong((ulong *)&bp->bp_id) != BootpID) 100 retval = -6; 101 102 debug("Filtering pkt = %d\n", retval); 103 104 return retval; 105 } 106 107 /* 108 * Copy parameters of interest from BOOTP_REPLY/DHCP_OFFER packet 109 */ 110 static void BootpCopyNetParams(struct Bootp_t *bp) 111 { 112 #if !defined(CONFIG_BOOTP_SERVERIP) 113 IPaddr_t tmp_ip; 114 115 NetCopyIP(&tmp_ip, &bp->bp_siaddr); 116 if (tmp_ip != 0) 117 NetCopyIP(&NetServerIP, &bp->bp_siaddr); 118 memcpy(NetServerEther, ((struct ethernet_hdr *)NetRxPacket)->et_src, 6); 119 #endif 120 NetCopyIP(&NetOurIP, &bp->bp_yiaddr); 121 if (strlen(bp->bp_file) > 0) 122 copy_filename(BootFile, bp->bp_file, sizeof(BootFile)); 123 124 debug("Bootfile: %s\n", BootFile); 125 126 /* Propagate to environment: 127 * don't delete exising entry when BOOTP / DHCP reply does 128 * not contain a new value 129 */ 130 if (*BootFile) 131 setenv("bootfile", BootFile); 132 } 133 134 static int truncate_sz(const char *name, int maxlen, int curlen) 135 { 136 if (curlen >= maxlen) { 137 printf("*** WARNING: %s is too long (%d - max: %d)" 138 " - truncated\n", name, curlen, maxlen); 139 curlen = maxlen - 1; 140 } 141 return curlen; 142 } 143 144 #if !defined(CONFIG_CMD_DHCP) 145 146 static void BootpVendorFieldProcess(u8 *ext) 147 { 148 int size = *(ext + 1); 149 150 debug("[BOOTP] Processing extension %d... (%d bytes)\n", *ext, 151 *(ext + 1)); 152 153 NetBootFileSize = 0; 154 155 switch (*ext) { 156 /* Fixed length fields */ 157 case 1: /* Subnet mask */ 158 if (NetOurSubnetMask == 0) 159 NetCopyIP(&NetOurSubnetMask, (IPaddr_t *) (ext + 2)); 160 break; 161 case 2: /* Time offset - Not yet supported */ 162 break; 163 /* Variable length fields */ 164 case 3: /* Gateways list */ 165 if (NetOurGatewayIP == 0) 166 NetCopyIP(&NetOurGatewayIP, (IPaddr_t *) (ext + 2)); 167 break; 168 case 4: /* Time server - Not yet supported */ 169 break; 170 case 5: /* IEN-116 name server - Not yet supported */ 171 break; 172 case 6: 173 if (NetOurDNSIP == 0) 174 NetCopyIP(&NetOurDNSIP, (IPaddr_t *) (ext + 2)); 175 #if defined(CONFIG_BOOTP_DNS2) 176 if ((NetOurDNS2IP == 0) && (size > 4)) 177 NetCopyIP(&NetOurDNS2IP, (IPaddr_t *) (ext + 2 + 4)); 178 #endif 179 break; 180 case 7: /* Log server - Not yet supported */ 181 break; 182 case 8: /* Cookie/Quote server - Not yet supported */ 183 break; 184 case 9: /* LPR server - Not yet supported */ 185 break; 186 case 10: /* Impress server - Not yet supported */ 187 break; 188 case 11: /* RPL server - Not yet supported */ 189 break; 190 case 12: /* Host name */ 191 if (NetOurHostName[0] == 0) { 192 size = truncate_sz("Host Name", 193 sizeof(NetOurHostName), size); 194 memcpy(&NetOurHostName, ext + 2, size); 195 NetOurHostName[size] = 0; 196 } 197 break; 198 case 13: /* Boot file size */ 199 if (size == 2) 200 NetBootFileSize = ntohs(*(ushort *) (ext + 2)); 201 else if (size == 4) 202 NetBootFileSize = ntohl(*(ulong *) (ext + 2)); 203 break; 204 case 14: /* Merit dump file - Not yet supported */ 205 break; 206 case 15: /* Domain name - Not yet supported */ 207 break; 208 case 16: /* Swap server - Not yet supported */ 209 break; 210 case 17: /* Root path */ 211 if (NetOurRootPath[0] == 0) { 212 size = truncate_sz("Root Path", 213 sizeof(NetOurRootPath), size); 214 memcpy(&NetOurRootPath, ext + 2, size); 215 NetOurRootPath[size] = 0; 216 } 217 break; 218 case 18: /* Extension path - Not yet supported */ 219 /* 220 * This can be used to send the information of the 221 * vendor area in another file that the client can 222 * access via TFTP. 223 */ 224 break; 225 /* IP host layer fields */ 226 case 40: /* NIS Domain name */ 227 if (NetOurNISDomain[0] == 0) { 228 size = truncate_sz("NIS Domain Name", 229 sizeof(NetOurNISDomain), size); 230 memcpy(&NetOurNISDomain, ext + 2, size); 231 NetOurNISDomain[size] = 0; 232 } 233 break; 234 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER) 235 case 42: /* NTP server IP */ 236 NetCopyIP(&NetNtpServerIP, (IPaddr_t *) (ext + 2)); 237 break; 238 #endif 239 /* Application layer fields */ 240 case 43: /* Vendor specific info - Not yet supported */ 241 /* 242 * Binary information to exchange specific 243 * product information. 244 */ 245 break; 246 /* Reserved (custom) fields (128..254) */ 247 } 248 } 249 250 static void BootpVendorProcess(u8 *ext, int size) 251 { 252 u8 *end = ext + size; 253 254 debug("[BOOTP] Checking extension (%d bytes)...\n", size); 255 256 while ((ext < end) && (*ext != 0xff)) { 257 if (*ext == 0) { 258 ext++; 259 } else { 260 u8 *opt = ext; 261 262 ext += ext[1] + 2; 263 if (ext <= end) 264 BootpVendorFieldProcess(opt); 265 } 266 } 267 268 debug("[BOOTP] Received fields:\n"); 269 if (NetOurSubnetMask) 270 debug("NetOurSubnetMask : %pI4\n", &NetOurSubnetMask); 271 272 if (NetOurGatewayIP) 273 debug("NetOurGatewayIP : %pI4", &NetOurGatewayIP); 274 275 if (NetBootFileSize) 276 debug("NetBootFileSize : %d\n", NetBootFileSize); 277 278 if (NetOurHostName[0]) 279 debug("NetOurHostName : %s\n", NetOurHostName); 280 281 if (NetOurRootPath[0]) 282 debug("NetOurRootPath : %s\n", NetOurRootPath); 283 284 if (NetOurNISDomain[0]) 285 debug("NetOurNISDomain : %s\n", NetOurNISDomain); 286 287 if (NetBootFileSize) 288 debug("NetBootFileSize: %d\n", NetBootFileSize); 289 290 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER) 291 if (NetNtpServerIP) 292 debug("NetNtpServerIP : %pI4\n", &NetNtpServerIP); 293 #endif 294 } 295 296 /* 297 * Handle a BOOTP received packet. 298 */ 299 static void 300 BootpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, 301 unsigned len) 302 { 303 struct Bootp_t *bp; 304 305 debug("got BOOTP packet (src=%d, dst=%d, len=%d want_len=%zu)\n", 306 src, dest, len, sizeof(struct Bootp_t)); 307 308 bp = (struct Bootp_t *)pkt; 309 310 /* Filter out pkts we don't want */ 311 if (BootpCheckPkt(pkt, dest, src, len)) 312 return; 313 314 /* 315 * Got a good BOOTP reply. Copy the data into our variables. 316 */ 317 #ifdef CONFIG_STATUS_LED 318 status_led_set(STATUS_LED_BOOT, STATUS_LED_OFF); 319 #endif 320 321 BootpCopyNetParams(bp); /* Store net parameters from reply */ 322 323 /* Retrieve extended information (we must parse the vendor area) */ 324 if (NetReadLong((ulong *)&bp->bp_vend[0]) == htonl(BOOTP_VENDOR_MAGIC)) 325 BootpVendorProcess((uchar *)&bp->bp_vend[4], len); 326 327 NetSetTimeout(0, (thand_f *)0); 328 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, "bootp_stop"); 329 330 debug("Got good BOOTP\n"); 331 332 net_auto_load(); 333 } 334 #endif 335 336 /* 337 * Timeout on BOOTP/DHCP request. 338 */ 339 static void 340 BootpTimeout(void) 341 { 342 ulong time_taken = get_timer(bootp_start); 343 344 if (time_taken >= TIMEOUT_MS) { 345 #ifdef CONFIG_BOOTP_MAY_FAIL 346 puts("\nRetry time exceeded\n"); 347 net_set_state(NETLOOP_FAIL); 348 #else 349 puts("\nRetry time exceeded; starting again\n"); 350 NetStartAgain(); 351 #endif 352 } else { 353 bootp_timeout *= 2; 354 if (bootp_timeout > 1000) 355 bootp_timeout = 1000; 356 NetSetTimeout(bootp_timeout, BootpTimeout); 357 BootpRequest(); 358 } 359 } 360 361 #define put_vci(e, str) \ 362 do { \ 363 size_t vci_strlen = strlen(str); \ 364 *e++ = 60; /* Vendor Class Identifier */ \ 365 *e++ = vci_strlen; \ 366 memcpy(e, str, vci_strlen); \ 367 e += vci_strlen; \ 368 } while (0) 369 370 /* 371 * Initialize BOOTP extension fields in the request. 372 */ 373 #if defined(CONFIG_CMD_DHCP) 374 static int DhcpExtended(u8 *e, int message_type, IPaddr_t ServerID, 375 IPaddr_t RequestedIP) 376 { 377 u8 *start = e; 378 u8 *cnt; 379 #if defined(CONFIG_BOOTP_PXE) 380 char *uuid; 381 u16 clientarch; 382 #endif 383 384 #if defined(CONFIG_BOOTP_VENDOREX) 385 u8 *x; 386 #endif 387 #if defined(CONFIG_BOOTP_SEND_HOSTNAME) 388 char *hostname; 389 #endif 390 391 *e++ = 99; /* RFC1048 Magic Cookie */ 392 *e++ = 130; 393 *e++ = 83; 394 *e++ = 99; 395 396 *e++ = 53; /* DHCP Message Type */ 397 *e++ = 1; 398 *e++ = message_type; 399 400 *e++ = 57; /* Maximum DHCP Message Size */ 401 *e++ = 2; 402 *e++ = (576 - 312 + OPT_FIELD_SIZE) >> 8; 403 *e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff; 404 405 if (ServerID) { 406 int tmp = ntohl(ServerID); 407 408 *e++ = 54; /* ServerID */ 409 *e++ = 4; 410 *e++ = tmp >> 24; 411 *e++ = tmp >> 16; 412 *e++ = tmp >> 8; 413 *e++ = tmp & 0xff; 414 } 415 416 if (RequestedIP) { 417 int tmp = ntohl(RequestedIP); 418 419 *e++ = 50; /* Requested IP */ 420 *e++ = 4; 421 *e++ = tmp >> 24; 422 *e++ = tmp >> 16; 423 *e++ = tmp >> 8; 424 *e++ = tmp & 0xff; 425 } 426 #if defined(CONFIG_BOOTP_SEND_HOSTNAME) 427 hostname = getenv("hostname"); 428 if (hostname) { 429 int hostnamelen = strlen(hostname); 430 431 *e++ = 12; /* Hostname */ 432 *e++ = hostnamelen; 433 memcpy(e, hostname, hostnamelen); 434 e += hostnamelen; 435 } 436 #endif 437 438 #if defined(CONFIG_BOOTP_PXE) 439 clientarch = CONFIG_BOOTP_PXE_CLIENTARCH; 440 *e++ = 93; /* Client System Architecture */ 441 *e++ = 2; 442 *e++ = (clientarch >> 8) & 0xff; 443 *e++ = clientarch & 0xff; 444 445 *e++ = 94; /* Client Network Interface Identifier */ 446 *e++ = 3; 447 *e++ = 1; /* type field for UNDI */ 448 *e++ = 0; /* major revision */ 449 *e++ = 0; /* minor revision */ 450 451 uuid = getenv("pxeuuid"); 452 453 if (uuid) { 454 if (uuid_str_valid(uuid)) { 455 *e++ = 97; /* Client Machine Identifier */ 456 *e++ = 17; 457 *e++ = 0; /* type 0 - UUID */ 458 459 uuid_str_to_bin(uuid, e, UUID_STR_FORMAT_STD); 460 e += 16; 461 } else { 462 printf("Invalid pxeuuid: %s\n", uuid); 463 } 464 } 465 #endif 466 467 #ifdef CONFIG_BOOTP_VCI_STRING 468 put_vci(e, CONFIG_BOOTP_VCI_STRING); 469 #endif 470 471 #if defined(CONFIG_BOOTP_VENDOREX) 472 x = dhcp_vendorex_prep(e); 473 if (x) 474 return x - start; 475 #endif 476 477 *e++ = 55; /* Parameter Request List */ 478 cnt = e++; /* Pointer to count of requested items */ 479 *cnt = 0; 480 #if defined(CONFIG_BOOTP_SUBNETMASK) 481 *e++ = 1; /* Subnet Mask */ 482 *cnt += 1; 483 #endif 484 #if defined(CONFIG_BOOTP_TIMEOFFSET) 485 *e++ = 2; 486 *cnt += 1; 487 #endif 488 #if defined(CONFIG_BOOTP_GATEWAY) 489 *e++ = 3; /* Router Option */ 490 *cnt += 1; 491 #endif 492 #if defined(CONFIG_BOOTP_DNS) 493 *e++ = 6; /* DNS Server(s) */ 494 *cnt += 1; 495 #endif 496 #if defined(CONFIG_BOOTP_HOSTNAME) 497 *e++ = 12; /* Hostname */ 498 *cnt += 1; 499 #endif 500 #if defined(CONFIG_BOOTP_BOOTFILESIZE) 501 *e++ = 13; /* Boot File Size */ 502 *cnt += 1; 503 #endif 504 #if defined(CONFIG_BOOTP_BOOTPATH) 505 *e++ = 17; /* Boot path */ 506 *cnt += 1; 507 #endif 508 #if defined(CONFIG_BOOTP_NISDOMAIN) 509 *e++ = 40; /* NIS Domain name request */ 510 *cnt += 1; 511 #endif 512 #if defined(CONFIG_BOOTP_NTPSERVER) 513 *e++ = 42; 514 *cnt += 1; 515 #endif 516 /* no options, so back up to avoid sending an empty request list */ 517 if (*cnt == 0) 518 e -= 2; 519 520 *e++ = 255; /* End of the list */ 521 522 /* Pad to minimal length */ 523 #ifdef CONFIG_DHCP_MIN_EXT_LEN 524 while ((e - start) < CONFIG_DHCP_MIN_EXT_LEN) 525 *e++ = 0; 526 #endif 527 528 return e - start; 529 } 530 531 #else 532 /* 533 * Warning: no field size check - change CONFIG_BOOTP_* at your own risk! 534 */ 535 static int BootpExtended(u8 *e) 536 { 537 u8 *start = e; 538 539 *e++ = 99; /* RFC1048 Magic Cookie */ 540 *e++ = 130; 541 *e++ = 83; 542 *e++ = 99; 543 544 #if defined(CONFIG_CMD_DHCP) 545 *e++ = 53; /* DHCP Message Type */ 546 *e++ = 1; 547 *e++ = DHCP_DISCOVER; 548 549 *e++ = 57; /* Maximum DHCP Message Size */ 550 *e++ = 2; 551 *e++ = (576 - 312 + OPT_FIELD_SIZE) >> 16; 552 *e++ = (576 - 312 + OPT_FIELD_SIZE) & 0xff; 553 #endif 554 555 #if defined(CONFIG_BOOTP_VCI_STRING) || \ 556 (defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_NET_VCI_STRING)) 557 #ifdef CONFIG_SPL_BUILD 558 put_vci(e, CONFIG_SPL_NET_VCI_STRING); 559 #else 560 put_vci(e, CONFIG_BOOTP_VCI_STRING); 561 #endif 562 #endif 563 564 #if defined(CONFIG_BOOTP_SUBNETMASK) 565 *e++ = 1; /* Subnet mask request */ 566 *e++ = 4; 567 e += 4; 568 #endif 569 570 #if defined(CONFIG_BOOTP_GATEWAY) 571 *e++ = 3; /* Default gateway request */ 572 *e++ = 4; 573 e += 4; 574 #endif 575 576 #if defined(CONFIG_BOOTP_DNS) 577 *e++ = 6; /* Domain Name Server */ 578 *e++ = 4; 579 e += 4; 580 #endif 581 582 #if defined(CONFIG_BOOTP_HOSTNAME) 583 *e++ = 12; /* Host name request */ 584 *e++ = 32; 585 e += 32; 586 #endif 587 588 #if defined(CONFIG_BOOTP_BOOTFILESIZE) 589 *e++ = 13; /* Boot file size */ 590 *e++ = 2; 591 e += 2; 592 #endif 593 594 #if defined(CONFIG_BOOTP_BOOTPATH) 595 *e++ = 17; /* Boot path */ 596 *e++ = 32; 597 e += 32; 598 #endif 599 600 #if defined(CONFIG_BOOTP_NISDOMAIN) 601 *e++ = 40; /* NIS Domain name request */ 602 *e++ = 32; 603 e += 32; 604 #endif 605 #if defined(CONFIG_BOOTP_NTPSERVER) 606 *e++ = 42; 607 *e++ = 4; 608 e += 4; 609 #endif 610 611 *e++ = 255; /* End of the list */ 612 613 return e - start; 614 } 615 #endif 616 617 void BootpReset(void) 618 { 619 BootpTry = 0; 620 bootp_start = get_timer(0); 621 bootp_timeout = 10; 622 } 623 624 void 625 BootpRequest(void) 626 { 627 uchar *pkt, *iphdr; 628 struct Bootp_t *bp; 629 int extlen, pktlen, iplen; 630 int eth_hdr_size; 631 #ifdef CONFIG_BOOTP_RANDOM_DELAY 632 ulong rand_ms; 633 #endif 634 635 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_START, "bootp_start"); 636 #if defined(CONFIG_CMD_DHCP) 637 dhcp_state = INIT; 638 #endif 639 640 #ifdef CONFIG_BOOTP_RANDOM_DELAY /* Random BOOTP delay */ 641 if (BootpTry == 0) 642 srand_mac(); 643 644 if (BootpTry <= 2) /* Start with max 1024 * 1ms */ 645 rand_ms = rand() >> (22 - BootpTry); 646 else /* After 3rd BOOTP request max 8192 * 1ms */ 647 rand_ms = rand() >> 19; 648 649 printf("Random delay: %ld ms...\n", rand_ms); 650 mdelay(rand_ms); 651 652 #endif /* CONFIG_BOOTP_RANDOM_DELAY */ 653 654 printf("BOOTP broadcast %d\n", ++BootpTry); 655 pkt = NetTxPacket; 656 memset((void *)pkt, 0, PKTSIZE); 657 658 eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP); 659 pkt += eth_hdr_size; 660 661 /* 662 * Next line results in incorrect packet size being transmitted, 663 * resulting in errors in some DHCP servers, reporting missing bytes. 664 * Size must be set in packet header after extension length has been 665 * determined. 666 * C. Hallinan, DS4.COM, Inc. 667 */ 668 /* net_set_udp_header(pkt, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, 669 sizeof (struct Bootp_t)); */ 670 iphdr = pkt; /* We need this later for net_set_udp_header() */ 671 pkt += IP_UDP_HDR_SIZE; 672 673 bp = (struct Bootp_t *)pkt; 674 bp->bp_op = OP_BOOTREQUEST; 675 bp->bp_htype = HWT_ETHER; 676 bp->bp_hlen = HWL_ETHER; 677 bp->bp_hops = 0; 678 bp->bp_secs = htons(get_timer(0) / 1000); 679 NetWriteIP(&bp->bp_ciaddr, 0); 680 NetWriteIP(&bp->bp_yiaddr, 0); 681 NetWriteIP(&bp->bp_siaddr, 0); 682 NetWriteIP(&bp->bp_giaddr, 0); 683 memcpy(bp->bp_chaddr, NetOurEther, 6); 684 copy_filename(bp->bp_file, BootFile, sizeof(bp->bp_file)); 685 686 /* Request additional information from the BOOTP/DHCP server */ 687 #if defined(CONFIG_CMD_DHCP) 688 extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_DISCOVER, 0, 0); 689 #else 690 extlen = BootpExtended((u8 *)bp->bp_vend); 691 #endif 692 693 /* 694 * Bootp ID is the lower 4 bytes of our ethernet address 695 * plus the current time in ms. 696 */ 697 BootpID = ((ulong)NetOurEther[2] << 24) 698 | ((ulong)NetOurEther[3] << 16) 699 | ((ulong)NetOurEther[4] << 8) 700 | (ulong)NetOurEther[5]; 701 BootpID += get_timer(0); 702 BootpID = htonl(BootpID); 703 NetCopyLong(&bp->bp_id, &BootpID); 704 705 /* 706 * Calculate proper packet lengths taking into account the 707 * variable size of the options field 708 */ 709 iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen; 710 pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen; 711 net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen); 712 NetSetTimeout(bootp_timeout, BootpTimeout); 713 714 #if defined(CONFIG_CMD_DHCP) 715 dhcp_state = SELECTING; 716 net_set_udp_handler(DhcpHandler); 717 #else 718 net_set_udp_handler(BootpHandler); 719 #endif 720 NetSendPacket(NetTxPacket, pktlen); 721 } 722 723 #if defined(CONFIG_CMD_DHCP) 724 static void DhcpOptionsProcess(uchar *popt, struct Bootp_t *bp) 725 { 726 uchar *end = popt + BOOTP_HDR_SIZE; 727 int oplen, size; 728 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET) 729 int *to_ptr; 730 #endif 731 732 while (popt < end && *popt != 0xff) { 733 oplen = *(popt + 1); 734 switch (*popt) { 735 case 1: 736 NetCopyIP(&NetOurSubnetMask, (popt + 2)); 737 break; 738 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_TIMEOFFSET) 739 case 2: /* Time offset */ 740 to_ptr = &NetTimeOffset; 741 NetCopyLong((ulong *)to_ptr, (ulong *)(popt + 2)); 742 NetTimeOffset = ntohl(NetTimeOffset); 743 break; 744 #endif 745 case 3: 746 NetCopyIP(&NetOurGatewayIP, (popt + 2)); 747 break; 748 case 6: 749 NetCopyIP(&NetOurDNSIP, (popt + 2)); 750 #if defined(CONFIG_BOOTP_DNS2) 751 if (*(popt + 1) > 4) 752 NetCopyIP(&NetOurDNS2IP, (popt + 2 + 4)); 753 #endif 754 break; 755 case 12: 756 size = truncate_sz("Host Name", 757 sizeof(NetOurHostName), oplen); 758 memcpy(&NetOurHostName, popt + 2, size); 759 NetOurHostName[size] = 0; 760 break; 761 case 15: /* Ignore Domain Name Option */ 762 break; 763 case 17: 764 size = truncate_sz("Root Path", 765 sizeof(NetOurRootPath), oplen); 766 memcpy(&NetOurRootPath, popt + 2, size); 767 NetOurRootPath[size] = 0; 768 break; 769 case 28: /* Ignore Broadcast Address Option */ 770 break; 771 #if defined(CONFIG_CMD_SNTP) && defined(CONFIG_BOOTP_NTPSERVER) 772 case 42: /* NTP server IP */ 773 NetCopyIP(&NetNtpServerIP, (popt + 2)); 774 break; 775 #endif 776 case 51: 777 NetCopyLong(&dhcp_leasetime, (ulong *) (popt + 2)); 778 break; 779 case 53: /* Ignore Message Type Option */ 780 break; 781 case 54: 782 NetCopyIP(&NetDHCPServerIP, (popt + 2)); 783 break; 784 case 58: /* Ignore Renewal Time Option */ 785 break; 786 case 59: /* Ignore Rebinding Time Option */ 787 break; 788 case 66: /* Ignore TFTP server name */ 789 break; 790 case 67: /* vendor opt bootfile */ 791 /* 792 * I can't use dhcp_vendorex_proc here because I need 793 * to write into the bootp packet - even then I had to 794 * pass the bootp packet pointer into here as the 795 * second arg 796 */ 797 size = truncate_sz("Opt Boot File", 798 sizeof(bp->bp_file), 799 oplen); 800 if (bp->bp_file[0] == '\0' && size > 0) { 801 /* 802 * only use vendor boot file if we didn't 803 * receive a boot file in the main non-vendor 804 * part of the packet - god only knows why 805 * some vendors chose not to use this perfectly 806 * good spot to store the boot file (join on 807 * Tru64 Unix) it seems mind bogglingly crazy 808 * to me 809 */ 810 printf("*** WARNING: using vendor " 811 "optional boot file\n"); 812 memcpy(bp->bp_file, popt + 2, size); 813 bp->bp_file[size] = '\0'; 814 } 815 break; 816 default: 817 #if defined(CONFIG_BOOTP_VENDOREX) 818 if (dhcp_vendorex_proc(popt)) 819 break; 820 #endif 821 printf("*** Unhandled DHCP Option in OFFER/ACK:" 822 " %d\n", *popt); 823 break; 824 } 825 popt += oplen + 2; /* Process next option */ 826 } 827 } 828 829 static int DhcpMessageType(unsigned char *popt) 830 { 831 if (NetReadLong((ulong *)popt) != htonl(BOOTP_VENDOR_MAGIC)) 832 return -1; 833 834 popt += 4; 835 while (*popt != 0xff) { 836 if (*popt == 53) /* DHCP Message Type */ 837 return *(popt + 2); 838 popt += *(popt + 1) + 2; /* Scan through all options */ 839 } 840 return -1; 841 } 842 843 static void DhcpSendRequestPkt(struct Bootp_t *bp_offer) 844 { 845 uchar *pkt, *iphdr; 846 struct Bootp_t *bp; 847 int pktlen, iplen, extlen; 848 int eth_hdr_size; 849 IPaddr_t OfferedIP; 850 851 debug("DhcpSendRequestPkt: Sending DHCPREQUEST\n"); 852 pkt = NetTxPacket; 853 memset((void *)pkt, 0, PKTSIZE); 854 855 eth_hdr_size = NetSetEther(pkt, NetBcastAddr, PROT_IP); 856 pkt += eth_hdr_size; 857 858 iphdr = pkt; /* We'll need this later to set proper pkt size */ 859 pkt += IP_UDP_HDR_SIZE; 860 861 bp = (struct Bootp_t *)pkt; 862 bp->bp_op = OP_BOOTREQUEST; 863 bp->bp_htype = HWT_ETHER; 864 bp->bp_hlen = HWL_ETHER; 865 bp->bp_hops = 0; 866 bp->bp_secs = htons(get_timer(0) / 1000); 867 /* Do not set the client IP, your IP, or server IP yet, since it 868 * hasn't been ACK'ed by the server yet */ 869 870 /* 871 * RFC3046 requires Relay Agents to discard packets with 872 * nonzero and offered giaddr 873 */ 874 NetWriteIP(&bp->bp_giaddr, 0); 875 876 memcpy(bp->bp_chaddr, NetOurEther, 6); 877 878 /* 879 * ID is the id of the OFFER packet 880 */ 881 882 NetCopyLong(&bp->bp_id, &bp_offer->bp_id); 883 884 /* 885 * Copy options from OFFER packet if present 886 */ 887 888 /* Copy offered IP into the parameters request list */ 889 NetCopyIP(&OfferedIP, &bp_offer->bp_yiaddr); 890 extlen = DhcpExtended((u8 *)bp->bp_vend, DHCP_REQUEST, 891 NetDHCPServerIP, OfferedIP); 892 893 iplen = BOOTP_HDR_SIZE - OPT_FIELD_SIZE + extlen; 894 pktlen = eth_hdr_size + IP_UDP_HDR_SIZE + iplen; 895 net_set_udp_header(iphdr, 0xFFFFFFFFL, PORT_BOOTPS, PORT_BOOTPC, iplen); 896 897 #ifdef CONFIG_BOOTP_DHCP_REQUEST_DELAY 898 udelay(CONFIG_BOOTP_DHCP_REQUEST_DELAY); 899 #endif /* CONFIG_BOOTP_DHCP_REQUEST_DELAY */ 900 debug("Transmitting DHCPREQUEST packet: len = %d\n", pktlen); 901 NetSendPacket(NetTxPacket, pktlen); 902 } 903 904 /* 905 * Handle DHCP received packets. 906 */ 907 static void 908 DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src, 909 unsigned len) 910 { 911 struct Bootp_t *bp = (struct Bootp_t *)pkt; 912 913 debug("DHCPHandler: got packet: (src=%d, dst=%d, len=%d) state: %d\n", 914 src, dest, len, dhcp_state); 915 916 /* Filter out pkts we don't want */ 917 if (BootpCheckPkt(pkt, dest, src, len)) 918 return; 919 920 debug("DHCPHandler: got DHCP packet: (src=%d, dst=%d, len=%d) state:" 921 " %d\n", src, dest, len, dhcp_state); 922 923 switch (dhcp_state) { 924 case SELECTING: 925 /* 926 * Wait an appropriate time for any potential DHCPOFFER packets 927 * to arrive. Then select one, and generate DHCPREQUEST 928 * response. If filename is in format we recognize, assume it 929 * is a valid OFFER from a server we want. 930 */ 931 debug("DHCP: state=SELECTING bp_file: \"%s\"\n", bp->bp_file); 932 #ifdef CONFIG_SYS_BOOTFILE_PREFIX 933 if (strncmp(bp->bp_file, 934 CONFIG_SYS_BOOTFILE_PREFIX, 935 strlen(CONFIG_SYS_BOOTFILE_PREFIX)) == 0) { 936 #endif /* CONFIG_SYS_BOOTFILE_PREFIX */ 937 938 debug("TRANSITIONING TO REQUESTING STATE\n"); 939 dhcp_state = REQUESTING; 940 941 if (NetReadLong((ulong *)&bp->bp_vend[0]) == 942 htonl(BOOTP_VENDOR_MAGIC)) 943 DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp); 944 945 NetSetTimeout(5000, BootpTimeout); 946 DhcpSendRequestPkt(bp); 947 #ifdef CONFIG_SYS_BOOTFILE_PREFIX 948 } 949 #endif /* CONFIG_SYS_BOOTFILE_PREFIX */ 950 951 return; 952 break; 953 case REQUESTING: 954 debug("DHCP State: REQUESTING\n"); 955 956 if (DhcpMessageType((u8 *)bp->bp_vend) == DHCP_ACK) { 957 if (NetReadLong((ulong *)&bp->bp_vend[0]) == 958 htonl(BOOTP_VENDOR_MAGIC)) 959 DhcpOptionsProcess((u8 *)&bp->bp_vend[4], bp); 960 /* Store net params from reply */ 961 BootpCopyNetParams(bp); 962 dhcp_state = BOUND; 963 printf("DHCP client bound to address %pI4\n", 964 &NetOurIP); 965 bootstage_mark_name(BOOTSTAGE_ID_BOOTP_STOP, 966 "bootp_stop"); 967 968 net_auto_load(); 969 return; 970 } 971 break; 972 case BOUND: 973 /* DHCP client bound to address */ 974 break; 975 default: 976 puts("DHCP: INVALID STATE\n"); 977 break; 978 } 979 980 } 981 982 void DhcpRequest(void) 983 { 984 BootpRequest(); 985 } 986 #endif /* CONFIG_CMD_DHCP */ 987