uboot/net/bootp.c
<<
>>
Prefs
   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
  54ulong           bootp_ids[CONFIG_BOOTP_ID_CACHE_SIZE];
  55unsigned int    bootp_num_ids;
  56int             BootpTry;
  57ulong           bootp_start;
  58ulong           bootp_timeout;
  59
  60#if defined(CONFIG_CMD_DHCP)
  61static dhcp_state_t dhcp_state = INIT;
  62static unsigned long dhcp_leasetime;
  63static IPaddr_t NetDHCPServerIP;
  64static void DhcpHandler(uchar *pkt, unsigned dest, IPaddr_t sip, unsigned src,
  65                        unsigned len);
  66
  67/* For Debug */
  68#if 0
  69static 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
  85static 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
  98static 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
 109static 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 */
 139static 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#endif
 149        NetCopyIP(&NetOurIP, &bp->bp_yiaddr);
 150        if (strlen(bp->bp_file) > 0)
 151                copy_filename(BootFile, bp->bp_file, sizeof(BootFile));
 152
 153        debug("Bootfile: %s\n", BootFile);
 154
 155        /* Propagate to environment:
 156         * don't delete exising entry when BOOTP / DHCP reply does
 157         * not contain a new value
 158         */
 159        if (*BootFile)
 160                setenv("bootfile", BootFile);
 161}
 162
 163static 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
 175static 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
 279static 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 */
 328static void
 329BootpHandler(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 */
 368static void
 369BootpTimeout(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)
 403static 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 */
 564static 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
 646void BootpReset(void)
 647{
 648        bootp_num_ids = 0;
 649        BootpTry = 0;
 650        bootp_start = get_timer(0);
 651        bootp_timeout = 250;
 652}
 653
 654void
 655BootpRequest(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)
 756static 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
 861static 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
 875static 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 */
 939static void
 940DhcpHandler(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
1014void DhcpRequest(void)
1015{
1016        BootpRequest();
1017}
1018#endif  /* CONFIG_CMD_DHCP */
1019