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