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