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