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