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