busybox/networking/udhcp/dhcpc.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * udhcp client
   4 *
   5 * Russ Dill <Russ.Dill@asu.edu> July 2001
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 */
  21#include <syslog.h>
  22/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */
  23#define WANT_PIDFILE 1
  24#include "common.h"
  25#include "dhcpd.h"
  26#include "dhcpc.h"
  27
  28#include <asm/types.h>
  29#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION)
  30# include <netpacket/packet.h>
  31# include <net/ethernet.h>
  32#else
  33# include <linux/if_packet.h>
  34# include <linux/if_ether.h>
  35#endif
  36#include <linux/filter.h>
  37
  38/* struct client_config_t client_config is in bb_common_bufsiz1 */
  39
  40
  41/*** Script execution code ***/
  42
  43/* get a rough idea of how long an option will be (rounding up...) */
  44static const uint8_t len_of_option_as_string[] = {
  45        [OPTION_IP              ] = sizeof("255.255.255.255 "),
  46        [OPTION_IP_PAIR         ] = sizeof("255.255.255.255 ") * 2,
  47        [OPTION_STATIC_ROUTES   ] = sizeof("255.255.255.255/32 255.255.255.255 "),
  48        [OPTION_STRING          ] = 1,
  49#if ENABLE_FEATURE_UDHCP_RFC3397
  50        [OPTION_DNS_STRING      ] = 1, /* unused */
  51        /* Hmmm, this severely overestimates size if SIP_SERVERS option
  52         * is in domain name form: N-byte option in binary form
  53         * mallocs ~16*N bytes. But it is freed almost at once.
  54         */
  55        [OPTION_SIP_SERVERS     ] = sizeof("255.255.255.255 "),
  56#endif
  57//      [OPTION_BOOLEAN         ] = sizeof("yes "),
  58        [OPTION_U8              ] = sizeof("255 "),
  59        [OPTION_U16             ] = sizeof("65535 "),
  60//      [OPTION_S16             ] = sizeof("-32768 "),
  61        [OPTION_U32             ] = sizeof("4294967295 "),
  62        [OPTION_S32             ] = sizeof("-2147483684 "),
  63};
  64
  65/* note: ip is a pointer to an IP in network order, possibly misaliged */
  66static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
  67{
  68        return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
  69}
  70
  71/* really simple implementation, just count the bits */
  72static int mton(uint32_t mask)
  73{
  74        int i = 0;
  75        mask = ntohl(mask); /* 111110000-like bit pattern */
  76        while (mask) {
  77                i++;
  78                mask <<= 1;
  79        }
  80        return i;
  81}
  82
  83/* Create "opt_name=opt_value" string */
  84static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name)
  85{
  86        unsigned upper_length;
  87        int len, type, optlen;
  88        char *dest, *ret;
  89
  90        /* option points to OPT_DATA, need to go back and get OPT_LEN */
  91        len = option[OPT_LEN - OPT_DATA];
  92        type = optflag->flags & OPTION_TYPE_MASK;
  93        optlen = dhcp_option_lengths[type];
  94        upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen);
  95
  96        dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
  97        dest += sprintf(ret, "%s=", opt_name);
  98
  99        while (len >= optlen) {
 100                switch (type) {
 101                case OPTION_IP_PAIR:
 102                        dest += sprint_nip(dest, "", option);
 103                        *dest++ = '/';
 104                        option += 4;
 105                        optlen = 4;
 106                case OPTION_IP:
 107                        dest += sprint_nip(dest, "", option);
 108// TODO: it can be a list only if (optflag->flags & OPTION_LIST).
 109// Should we bail out/warn if we see multi-ip option which is
 110// not allowed to be such? For example, DHCP_BROADCAST...
 111                        break;
 112//              case OPTION_BOOLEAN:
 113//                      dest += sprintf(dest, *option ? "yes" : "no");
 114//                      break;
 115                case OPTION_U8:
 116                        dest += sprintf(dest, "%u", *option);
 117                        break;
 118//              case OPTION_S16:
 119                case OPTION_U16: {
 120                        uint16_t val_u16;
 121                        move_from_unaligned16(val_u16, option);
 122                        dest += sprintf(dest, "%u", ntohs(val_u16));
 123                        break;
 124                }
 125                case OPTION_S32:
 126                case OPTION_U32: {
 127                        uint32_t val_u32;
 128                        move_from_unaligned32(val_u32, option);
 129                        dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32));
 130                        break;
 131                }
 132                case OPTION_STRING:
 133                        memcpy(dest, option, len);
 134                        dest[len] = '\0';
 135                        return ret;      /* Short circuit this case */
 136                case OPTION_STATIC_ROUTES: {
 137                        /* Option binary format:
 138                         * mask [one byte, 0..32]
 139                         * ip [big endian, 0..4 bytes depending on mask]
 140                         * router [big endian, 4 bytes]
 141                         * may be repeated
 142                         *
 143                         * We convert it to a string "IP/MASK ROUTER IP2/MASK2 ROUTER2"
 144                         */
 145                        const char *pfx = "";
 146
 147                        while (len >= 1 + 4) { /* mask + 0-byte ip + router */
 148                                uint32_t nip;
 149                                uint8_t *p;
 150                                unsigned mask;
 151                                int bytes;
 152
 153                                mask = *option++;
 154                                if (mask > 32)
 155                                        break;
 156                                len--;
 157
 158                                nip = 0;
 159                                p = (void*) &nip;
 160                                bytes = (mask + 7) / 8; /* 0 -> 0, 1..8 -> 1, 9..16 -> 2 etc */
 161                                while (--bytes >= 0) {
 162                                        *p++ = *option++;
 163                                        len--;
 164                                }
 165                                if (len < 4)
 166                                        break;
 167
 168                                /* print ip/mask */
 169                                dest += sprint_nip(dest, pfx, (void*) &nip);
 170                                pfx = " ";
 171                                dest += sprintf(dest, "/%u ", mask);
 172                                /* print router */
 173                                dest += sprint_nip(dest, "", option);
 174                                option += 4;
 175                                len -= 4;
 176                        }
 177
 178                        return ret;
 179                }
 180#if ENABLE_FEATURE_UDHCP_RFC3397
 181                case OPTION_DNS_STRING:
 182                        /* unpack option into dest; use ret for prefix (i.e., "optname=") */
 183                        dest = dname_dec(option, len, ret);
 184                        if (dest) {
 185                                free(ret);
 186                                return dest;
 187                        }
 188                        /* error. return "optname=" string */
 189                        return ret;
 190                case OPTION_SIP_SERVERS:
 191                        /* Option binary format:
 192                         * type: byte
 193                         * type=0: domain names, dns-compressed
 194                         * type=1: IP addrs
 195                         */
 196                        option++;
 197                        len--;
 198                        if (option[-1] == 0) {
 199                                dest = dname_dec(option, len, ret);
 200                                if (dest) {
 201                                        free(ret);
 202                                        return dest;
 203                                }
 204                        } else
 205                        if (option[-1] == 1) {
 206                                const char *pfx = "";
 207                                while (1) {
 208                                        len -= 4;
 209                                        if (len < 0)
 210                                                break;
 211                                        dest += sprint_nip(dest, pfx, option);
 212                                        pfx = " ";
 213                                        option += 4;
 214                                }
 215                        }
 216                        return ret;
 217#endif
 218                } /* switch */
 219                option += optlen;
 220                len -= optlen;
 221                if (len <= 0)
 222                        break;
 223                *dest++ = ' ';
 224                *dest = '\0';
 225        }
 226        return ret;
 227}
 228
 229/* put all the parameters into the environment */
 230static char **fill_envp(struct dhcp_packet *packet)
 231{
 232        int envc;
 233        int i;
 234        char **envp, **curr;
 235        const char *opt_name;
 236        uint8_t *temp;
 237        uint8_t overload = 0;
 238
 239        /* We need 6 elements for:
 240         * "interface=IFACE"
 241         * "ip=N.N.N.N" from packet->yiaddr
 242         * "siaddr=IP" from packet->siaddr_nip (unless 0)
 243         * "boot_file=FILE" from packet->file (unless overloaded)
 244         * "sname=SERVER_HOSTNAME" from packet->sname (unless overloaded)
 245         * terminating NULL
 246         */
 247        envc = 6;
 248        /* +1 element for each option, +2 for subnet option: */
 249        if (packet) {
 250                for (i = 0; dhcp_optflags[i].code; i++) {
 251                        if (udhcp_get_option(packet, dhcp_optflags[i].code)) {
 252                                if (dhcp_optflags[i].code == DHCP_SUBNET)
 253                                        envc++; /* for mton */
 254                                envc++;
 255                        }
 256                }
 257                temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD);
 258                if (temp)
 259                        overload = *temp;
 260        }
 261        curr = envp = xzalloc(sizeof(char *) * envc);
 262
 263        *curr = xasprintf("interface=%s", client_config.interface);
 264        putenv(*curr++);
 265
 266        if (!packet)
 267                return envp;
 268
 269        *curr = xmalloc(sizeof("ip=255.255.255.255"));
 270        sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr);
 271        putenv(*curr++);
 272
 273        opt_name = dhcp_option_strings;
 274        i = 0;
 275        while (*opt_name) {
 276                temp = udhcp_get_option(packet, dhcp_optflags[i].code);
 277                if (!temp)
 278                        goto next;
 279                *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name);
 280                putenv(*curr++);
 281                if (dhcp_optflags[i].code == DHCP_SUBNET) {
 282                        /* Subnet option: make things like "$ip/$mask" possible */
 283                        uint32_t subnet;
 284                        move_from_unaligned32(subnet, temp);
 285                        *curr = xasprintf("mask=%d", mton(subnet));
 286                        putenv(*curr++);
 287                }
 288 next:
 289                opt_name += strlen(opt_name) + 1;
 290                i++;
 291        }
 292        if (packet->siaddr_nip) {
 293                *curr = xmalloc(sizeof("siaddr=255.255.255.255"));
 294                sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip);
 295                putenv(*curr++);
 296        }
 297        if (!(overload & FILE_FIELD) && packet->file[0]) {
 298                /* watch out for invalid packets */
 299                *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file);
 300                putenv(*curr++);
 301        }
 302        if (!(overload & SNAME_FIELD) && packet->sname[0]) {
 303                /* watch out for invalid packets */
 304                *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
 305                putenv(*curr++);
 306        }
 307        return envp;
 308}
 309
 310/* Call a script with a par file and env vars */
 311static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
 312{
 313        char **envp, **curr;
 314        char *argv[3];
 315
 316        if (client_config.script == NULL)
 317                return;
 318
 319        envp = fill_envp(packet);
 320
 321        /* call script */
 322        log1("Executing %s %s", client_config.script, name);
 323        argv[0] = (char*) client_config.script;
 324        argv[1] = (char*) name;
 325        argv[2] = NULL;
 326        spawn_and_wait(argv);
 327
 328        for (curr = envp; *curr; curr++) {
 329                log2(" %s", *curr);
 330                bb_unsetenv_and_free(*curr);
 331        }
 332        free(envp);
 333}
 334
 335
 336/*** Sending/receiving packets ***/
 337
 338static ALWAYS_INLINE uint32_t random_xid(void)
 339{
 340        return rand();
 341}
 342
 343/* Initialize the packet with the proper defaults */
 344static void init_packet(struct dhcp_packet *packet, char type)
 345{
 346        udhcp_init_header(packet, type);
 347        memcpy(packet->chaddr, client_config.client_mac, 6);
 348        if (client_config.clientid)
 349                udhcp_add_binary_option(packet, client_config.clientid);
 350        if (client_config.hostname)
 351                udhcp_add_binary_option(packet, client_config.hostname);
 352        if (client_config.fqdn)
 353                udhcp_add_binary_option(packet, client_config.fqdn);
 354        if (type != DHCPDECLINE
 355         && type != DHCPRELEASE
 356         && client_config.vendorclass
 357        ) {
 358                udhcp_add_binary_option(packet, client_config.vendorclass);
 359        }
 360}
 361
 362static void add_client_options(struct dhcp_packet *packet)
 363{
 364        /* Add a "param req" option with the list of options we'd like to have
 365         * from stubborn DHCP servers. Pull the data from the struct in common.c.
 366         * No bounds checking because it goes towards the head of the packet. */
 367        uint8_t c;
 368        int end = udhcp_end_option(packet->options);
 369        int i, len = 0;
 370
 371        for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) {
 372                if ((   (dhcp_optflags[i].flags & OPTION_REQ)
 373                     && !client_config.no_default_options
 374                    )
 375                 || (client_config.opt_mask[c >> 3] & (1 << (c & 7)))
 376                ) {
 377                        packet->options[end + OPT_DATA + len] = c;
 378                        len++;
 379                }
 380        }
 381        if (len) {
 382                packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
 383                packet->options[end + OPT_LEN] = len;
 384                packet->options[end + OPT_DATA + len] = DHCP_END;
 385        }
 386
 387        /* Add -x options if any */
 388        {
 389                struct option_set *curr = client_config.options;
 390                while (curr) {
 391                        udhcp_add_binary_option(packet, curr->data);
 392                        curr = curr->next;
 393                }
 394//              if (client_config.sname)
 395//                      strncpy((char*)packet->sname, client_config.sname, sizeof(packet->sname) - 1);
 396//              if (client_config.boot_file)
 397//                      strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1);
 398        }
 399}
 400
 401/* RFC 2131
 402 * 4.4.4 Use of broadcast and unicast
 403 *
 404 * The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM
 405 * messages, unless the client knows the address of a DHCP server.
 406 * The client unicasts DHCPRELEASE messages to the server. Because
 407 * the client is declining the use of the IP address supplied by the server,
 408 * the client broadcasts DHCPDECLINE messages.
 409 *
 410 * When the DHCP client knows the address of a DHCP server, in either
 411 * INIT or REBOOTING state, the client may use that address
 412 * in the DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address.
 413 * The client may also use unicast to send DHCPINFORM messages
 414 * to a known DHCP server. If the client receives no response to DHCP
 415 * messages sent to the IP address of a known DHCP server, the DHCP
 416 * client reverts to using the IP broadcast address.
 417 */
 418
 419static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet)
 420{
 421        return udhcp_send_raw_packet(packet,
 422                /*src*/ INADDR_ANY, CLIENT_PORT,
 423                /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
 424                client_config.ifindex);
 425}
 426
 427/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
 428static int send_discover(uint32_t xid, uint32_t requested)
 429{
 430        struct dhcp_packet packet;
 431
 432        init_packet(&packet, DHCPDISCOVER);
 433        packet.xid = xid;
 434        if (requested)
 435                udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
 436        /* Explicitly saying that we want RFC-compliant packets helps
 437         * some buggy DHCP servers to NOT send bigger packets */
 438        udhcp_add_simple_option(&packet, DHCP_MAX_SIZE, htons(576));
 439        add_client_options(&packet);
 440
 441        bb_info_msg("Sending discover...");
 442        return raw_bcast_from_client_config_ifindex(&packet);
 443}
 444
 445/* Broadcast a DHCP request message */
 446/* RFC 2131 3.1 paragraph 3:
 447 * "The client _broadcasts_ a DHCPREQUEST message..."
 448 */
 449static int send_select(uint32_t xid, uint32_t server, uint32_t requested)
 450{
 451        struct dhcp_packet packet;
 452        struct in_addr addr;
 453
 454        init_packet(&packet, DHCPREQUEST);
 455        packet.xid = xid;
 456        udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
 457        udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
 458        add_client_options(&packet);
 459
 460        addr.s_addr = requested;
 461        bb_info_msg("Sending select for %s...", inet_ntoa(addr));
 462        return raw_bcast_from_client_config_ifindex(&packet);
 463}
 464
 465/* Unicast or broadcast a DHCP renew message */
 466static int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
 467{
 468        struct dhcp_packet packet;
 469
 470        init_packet(&packet, DHCPREQUEST);
 471        packet.xid = xid;
 472        packet.ciaddr = ciaddr;
 473        add_client_options(&packet);
 474
 475        bb_info_msg("Sending renew...");
 476        if (server)
 477                return udhcp_send_kernel_packet(&packet,
 478                        ciaddr, CLIENT_PORT,
 479                        server, SERVER_PORT);
 480        return raw_bcast_from_client_config_ifindex(&packet);
 481}
 482
 483#if ENABLE_FEATURE_UDHCPC_ARPING
 484/* Broadcast a DHCP decline message */
 485static int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
 486{
 487        struct dhcp_packet packet;
 488
 489        init_packet(&packet, DHCPDECLINE);
 490        packet.xid = xid;
 491        udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
 492        udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
 493
 494        bb_info_msg("Sending decline...");
 495        return raw_bcast_from_client_config_ifindex(&packet);
 496}
 497#endif
 498
 499/* Unicast a DHCP release message */
 500static int send_release(uint32_t server, uint32_t ciaddr)
 501{
 502        struct dhcp_packet packet;
 503
 504        init_packet(&packet, DHCPRELEASE);
 505        packet.xid = random_xid();
 506        packet.ciaddr = ciaddr;
 507
 508        udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
 509
 510        bb_info_msg("Sending release...");
 511        return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
 512}
 513
 514/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
 515static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
 516{
 517        int bytes;
 518        struct ip_udp_dhcp_packet packet;
 519        uint16_t check;
 520
 521        memset(&packet, 0, sizeof(packet));
 522        bytes = safe_read(fd, &packet, sizeof(packet));
 523        if (bytes < 0) {
 524                log1("Packet read error, ignoring");
 525                /* NB: possible down interface, etc. Caller should pause. */
 526                return bytes; /* returns -1 */
 527        }
 528
 529        if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) {
 530                log1("Packet is too short, ignoring");
 531                return -2;
 532        }
 533
 534        if (bytes < ntohs(packet.ip.tot_len)) {
 535                /* packet is bigger than sizeof(packet), we did partial read */
 536                log1("Oversized packet, ignoring");
 537                return -2;
 538        }
 539
 540        /* ignore any extra garbage bytes */
 541        bytes = ntohs(packet.ip.tot_len);
 542
 543        /* make sure its the right packet for us, and that it passes sanity checks */
 544        if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION
 545         || packet.ip.ihl != (sizeof(packet.ip) >> 2)
 546         || packet.udp.dest != htons(CLIENT_PORT)
 547        /* || bytes > (int) sizeof(packet) - can't happen */
 548         || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip))
 549        ) {
 550                log1("Unrelated/bogus packet, ignoring");
 551                return -2;
 552        }
 553
 554        /* verify IP checksum */
 555        check = packet.ip.check;
 556        packet.ip.check = 0;
 557        if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) {
 558                log1("Bad IP header checksum, ignoring");
 559                return -2;
 560        }
 561
 562        /* verify UDP checksum. IP header has to be modified for this */
 563        memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
 564        /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
 565        packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
 566        check = packet.udp.check;
 567        packet.udp.check = 0;
 568        if (check && check != udhcp_checksum(&packet, bytes)) {
 569                log1("Packet with bad UDP checksum received, ignoring");
 570                return -2;
 571        }
 572
 573        memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
 574
 575        if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) {
 576                bb_info_msg("Packet with bad magic, ignoring");
 577                return -2;
 578        }
 579        log1("Got valid DHCP packet");
 580        udhcp_dump_packet(dhcp_pkt);
 581        return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
 582}
 583
 584
 585/*** Main ***/
 586
 587static int sockfd = -1;
 588
 589#define LISTEN_NONE   0
 590#define LISTEN_KERNEL 1
 591#define LISTEN_RAW    2
 592static smallint listen_mode;
 593
 594/* initial state: (re)start DHCP negotiation */
 595#define INIT_SELECTING  0
 596/* discover was sent, DHCPOFFER reply received */
 597#define REQUESTING      1
 598/* select/renew was sent, DHCPACK reply received */
 599#define BOUND           2
 600/* half of lease passed, want to renew it by sending unicast renew requests */
 601#define RENEWING        3
 602/* renew requests were not answered, lease is almost over, send broadcast renew */
 603#define REBINDING       4
 604/* manually requested renew (SIGUSR1) */
 605#define RENEW_REQUESTED 5
 606/* release, possibly manually requested (SIGUSR2) */
 607#define RELEASED        6
 608static smallint state;
 609
 610static int udhcp_raw_socket(int ifindex)
 611{
 612        int fd;
 613        struct sockaddr_ll sock;
 614
 615        /*
 616         * Comment:
 617         *
 618         *      I've selected not to see LL header, so BPF doesn't see it, too.
 619         *      The filter may also pass non-IP and non-ARP packets, but we do
 620         *      a more complete check when receiving the message in userspace.
 621         *
 622         * and filter shamelessly stolen from:
 623         *
 624         *      http://www.flamewarmaster.de/software/dhcpclient/
 625         *
 626         * There are a few other interesting ideas on that page (look under
 627         * "Motivation").  Use of netlink events is most interesting.  Think
 628         * of various network servers listening for events and reconfiguring.
 629         * That would obsolete sending HUP signals and/or make use of restarts.
 630         *
 631         * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
 632         * License: GPL v2.
 633         *
 634         * TODO: make conditional?
 635         */
 636#define SERVER_AND_CLIENT_PORTS  ((67 << 16) + 68)
 637        static const struct sock_filter filter_instr[] = {
 638                /* check for udp */
 639                BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
 640                BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0),     /* L5, L1, is UDP? */
 641                /* ugly check for arp on ethernet-like and IPv4 */
 642                BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),                      /* L1: */
 643                BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4),      /* L3, L4 */
 644                /* skip IP header */
 645                BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),                     /* L5: */
 646                /* check udp source and destination ports */
 647                BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
 648                BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */
 649                /* returns */
 650                BPF_STMT(BPF_RET|BPF_K, 0x0fffffff ),                   /* L3: pass */
 651                BPF_STMT(BPF_RET|BPF_K, 0),                             /* L4: reject */
 652        };
 653        static const struct sock_fprog filter_prog = {
 654                .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
 655                /* casting const away: */
 656                .filter = (struct sock_filter *) filter_instr,
 657        };
 658
 659        log1("Opening raw socket on ifindex %d", ifindex); //log2?
 660
 661        fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
 662        log1("Got raw socket fd %d", fd); //log2?
 663
 664        if (SERVER_PORT == 67 && CLIENT_PORT == 68) {
 665                /* Use only if standard ports are in use */
 666                /* Ignoring error (kernel may lack support for this) */
 667                if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
 668                                sizeof(filter_prog)) >= 0)
 669                        log1("Attached filter to raw socket fd %d", fd); // log?
 670        }
 671
 672        sock.sll_family = AF_PACKET;
 673        sock.sll_protocol = htons(ETH_P_IP);
 674        sock.sll_ifindex = ifindex;
 675        xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
 676        log1("Created raw socket");
 677
 678        return fd;
 679}
 680
 681static void change_listen_mode(int new_mode)
 682{
 683        log1("Entering listen mode: %s",
 684                new_mode != LISTEN_NONE
 685                        ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
 686                        : "none"
 687        );
 688
 689        listen_mode = new_mode;
 690        if (sockfd >= 0) {
 691                close(sockfd);
 692                sockfd = -1;
 693        }
 694        if (new_mode == LISTEN_KERNEL)
 695                sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
 696        else if (new_mode != LISTEN_NONE)
 697                sockfd = udhcp_raw_socket(client_config.ifindex);
 698        /* else LISTEN_NONE: sockfd stays closed */
 699}
 700
 701static void perform_renew(void)
 702{
 703        bb_info_msg("Performing a DHCP renew");
 704        switch (state) {
 705        case BOUND:
 706                change_listen_mode(LISTEN_KERNEL);
 707        case RENEWING:
 708        case REBINDING:
 709                state = RENEW_REQUESTED;
 710                break;
 711        case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
 712                udhcp_run_script(NULL, "deconfig");
 713        case REQUESTING:
 714        case RELEASED:
 715                change_listen_mode(LISTEN_RAW);
 716                state = INIT_SELECTING;
 717                break;
 718        case INIT_SELECTING:
 719                break;
 720        }
 721}
 722
 723static void perform_release(uint32_t requested_ip, uint32_t server_addr)
 724{
 725        char buffer[sizeof("255.255.255.255")];
 726        struct in_addr temp_addr;
 727
 728        /* send release packet */
 729        if (state == BOUND || state == RENEWING || state == REBINDING) {
 730                temp_addr.s_addr = server_addr;
 731                strcpy(buffer, inet_ntoa(temp_addr));
 732                temp_addr.s_addr = requested_ip;
 733                bb_info_msg("Unicasting a release of %s to %s",
 734                                inet_ntoa(temp_addr), buffer);
 735                send_release(server_addr, requested_ip); /* unicast */
 736                udhcp_run_script(NULL, "deconfig");
 737        }
 738        bb_info_msg("Entering released state");
 739
 740        change_listen_mode(LISTEN_NONE);
 741        state = RELEASED;
 742}
 743
 744static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
 745{
 746        uint8_t *storage;
 747        int len = strnlen(str, 255);
 748        storage = xzalloc(len + extra + OPT_DATA);
 749        storage[OPT_CODE] = code;
 750        storage[OPT_LEN] = len + extra;
 751        memcpy(storage + extra + OPT_DATA, str, len);
 752        return storage;
 753}
 754
 755#if BB_MMU
 756static void client_background(void)
 757{
 758        bb_daemonize(0);
 759        logmode &= ~LOGMODE_STDIO;
 760        /* rewrite pidfile, as our pid is different now */
 761        write_pidfile(client_config.pidfile);
 762}
 763#endif
 764
 765int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 766int udhcpc_main(int argc UNUSED_PARAM, char **argv)
 767{
 768        uint8_t *temp, *message;
 769        const char *str_c, *str_V, *str_h, *str_F, *str_r;
 770        IF_FEATURE_UDHCP_PORT(char *str_P;)
 771        llist_t *list_O = NULL;
 772        llist_t *list_x = NULL;
 773        int tryagain_timeout = 20;
 774        int discover_timeout = 3;
 775        int discover_retries = 3;
 776        uint32_t server_addr = server_addr; /* for compiler */
 777        uint32_t requested_ip = 0;
 778        uint32_t xid = 0;
 779        uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */
 780        int packet_num;
 781        int timeout; /* must be signed */
 782        unsigned already_waited_sec;
 783        unsigned opt;
 784        int max_fd;
 785        int retval;
 786        struct timeval tv;
 787        struct dhcp_packet packet;
 788        fd_set rfds;
 789
 790#if ENABLE_LONG_OPTS
 791        static const char udhcpc_longopts[] ALIGN1 =
 792                "clientid\0"       Required_argument "c"
 793                "clientid-none\0"  No_argument       "C"
 794                "vendorclass\0"    Required_argument "V"
 795                "hostname\0"       Required_argument "H"
 796                "fqdn\0"           Required_argument "F"
 797                "interface\0"      Required_argument "i"
 798                "now\0"            No_argument       "n"
 799                "pidfile\0"        Required_argument "p"
 800                "quit\0"           No_argument       "q"
 801                "release\0"        No_argument       "R"
 802                "request\0"        Required_argument "r"
 803                "script\0"         Required_argument "s"
 804                "timeout\0"        Required_argument "T"
 805                "version\0"        No_argument       "v"
 806                "retries\0"        Required_argument "t"
 807                "tryagain\0"       Required_argument "A"
 808                "syslog\0"         No_argument       "S"
 809                "request-option\0" Required_argument "O"
 810                "no-default-options\0" No_argument   "o"
 811                "foreground\0"     No_argument       "f"
 812                "background\0"     No_argument       "b"
 813                IF_FEATURE_UDHCPC_ARPING("arping\0"     No_argument       "a")
 814                IF_FEATURE_UDHCP_PORT("client-port\0"   Required_argument "P")
 815                ;
 816#endif
 817        enum {
 818                OPT_c = 1 << 0,
 819                OPT_C = 1 << 1,
 820                OPT_V = 1 << 2,
 821                OPT_H = 1 << 3,
 822                OPT_h = 1 << 4,
 823                OPT_F = 1 << 5,
 824                OPT_i = 1 << 6,
 825                OPT_n = 1 << 7,
 826                OPT_p = 1 << 8,
 827                OPT_q = 1 << 9,
 828                OPT_R = 1 << 10,
 829                OPT_r = 1 << 11,
 830                OPT_s = 1 << 12,
 831                OPT_T = 1 << 13,
 832                OPT_t = 1 << 14,
 833                OPT_S = 1 << 15,
 834                OPT_A = 1 << 16,
 835                OPT_O = 1 << 17,
 836                OPT_o = 1 << 18,
 837                OPT_x = 1 << 19,
 838                OPT_f = 1 << 20,
 839/* The rest has variable bit positions, need to be clever */
 840                OPTBIT_f = 20,
 841                USE_FOR_MMU(             OPTBIT_b,)
 842                IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
 843                IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
 844                USE_FOR_MMU(             OPT_b = 1 << OPTBIT_b,)
 845                IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
 846                IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
 847        };
 848
 849        /* Default options. */
 850        IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
 851        IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
 852        client_config.interface = "eth0";
 853        client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
 854        str_V = "udhcp "BB_VER;
 855
 856        /* Parse command line */
 857        /* Cc: mutually exclusive; O,x: list; -T,-t,-A take numeric param */
 858        opt_complementary = "c--C:C--c:O::x::T+:t+:A+"
 859#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
 860                ":vv"
 861#endif
 862                ;
 863        IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
 864        opt = getopt32(argv, "c:CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f"
 865                USE_FOR_MMU("b")
 866                IF_FEATURE_UDHCPC_ARPING("a")
 867                IF_FEATURE_UDHCP_PORT("P:")
 868                "v"
 869                , &str_c, &str_V, &str_h, &str_h, &str_F
 870                , &client_config.interface, &client_config.pidfile, &str_r /* i,p */
 871                , &client_config.script /* s */
 872                , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
 873                , &list_O
 874                , &list_x
 875                IF_FEATURE_UDHCP_PORT(, &str_P)
 876#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
 877                , &dhcp_verbose
 878#endif
 879                );
 880        if (opt & (OPT_h|OPT_H))
 881                client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
 882        if (opt & OPT_F) {
 883                /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */
 884                client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
 885                /* Flag bits: 0000NEOS
 886                 * S: 1 = Client requests server to update A RR in DNS as well as PTR
 887                 * O: 1 = Server indicates to client that DNS has been updated regardless
 888                 * E: 1 = Name is in DNS format, i.e. <4>host<6>domain<3>com<0>,
 889                 *    not "host.domain.com". Format 0 is obsolete.
 890                 * N: 1 = Client requests server to not update DNS (S must be 0 then)
 891                 * Two [0] bytes which follow are deprecated and must be 0.
 892                 */
 893                client_config.fqdn[OPT_DATA + 0] = 0x1;
 894                /*client_config.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */
 895                /*client_config.fqdn[OPT_DATA + 2] = 0; */
 896        }
 897        if (opt & OPT_r)
 898                requested_ip = inet_addr(str_r);
 899#if ENABLE_FEATURE_UDHCP_PORT
 900        if (opt & OPT_P) {
 901                CLIENT_PORT = xatou16(str_P);
 902                SERVER_PORT = CLIENT_PORT - 1;
 903        }
 904#endif
 905        if (opt & OPT_o)
 906                client_config.no_default_options = 1;
 907        while (list_O) {
 908                char *optstr = llist_pop(&list_O);
 909                unsigned n = udhcp_option_idx(optstr);
 910                n = dhcp_optflags[n].code;
 911                client_config.opt_mask[n >> 3] |= 1 << (n & 7);
 912        }
 913        while (list_x) {
 914                char *optstr = llist_pop(&list_x);
 915                char *colon = strchr(optstr, ':');
 916                if (colon)
 917                        *colon = ' ';
 918                /* now it looks similar to udhcpd's config file line:
 919                 * "optname optval", using the common routine: */
 920                udhcp_str2optset(optstr, &client_config.options);
 921        }
 922
 923        if (udhcp_read_interface(client_config.interface,
 924                        &client_config.ifindex,
 925                        NULL,
 926                        client_config.client_mac)
 927        ) {
 928                return 1;
 929        }
 930
 931        if (opt & OPT_c) {
 932                client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0);
 933        } else if (!(opt & OPT_C)) {
 934                /* not set and not suppressed, set the default client ID */
 935                client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
 936                client_config.clientid[OPT_DATA] = 1; /* type: ethernet */
 937                memcpy(client_config.clientid + OPT_DATA+1, client_config.client_mac, 6);
 938        }
 939        if (str_V[0] != '\0')
 940                client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
 941#if !BB_MMU
 942        /* on NOMMU reexec (i.e., background) early */
 943        if (!(opt & OPT_f)) {
 944                bb_daemonize_or_rexec(0 /* flags */, argv);
 945                logmode = LOGMODE_NONE;
 946        }
 947#endif
 948        if (opt & OPT_S) {
 949                openlog(applet_name, LOG_PID, LOG_DAEMON);
 950                logmode |= LOGMODE_SYSLOG;
 951        }
 952
 953        /* Make sure fd 0,1,2 are open */
 954        bb_sanitize_stdio();
 955        /* Equivalent of doing a fflush after every \n */
 956        setlinebuf(stdout);
 957        /* Create pidfile */
 958        write_pidfile(client_config.pidfile);
 959        /* Goes to stdout (unless NOMMU) and possibly syslog */
 960        bb_info_msg("%s (v"BB_VER") started", applet_name);
 961        /* Set up the signal pipe */
 962        udhcp_sp_setup();
 963        /* We want random_xid to be random... */
 964        srand(monotonic_us());
 965
 966        state = INIT_SELECTING;
 967        udhcp_run_script(NULL, "deconfig");
 968        change_listen_mode(LISTEN_RAW);
 969        packet_num = 0;
 970        timeout = 0;
 971        already_waited_sec = 0;
 972
 973        /* Main event loop. select() waits on signal pipe and possibly
 974         * on sockfd.
 975         * "continue" statements in code below jump to the top of the loop.
 976         */
 977        for (;;) {
 978                /* silence "uninitialized!" warning */
 979                unsigned timestamp_before_wait = timestamp_before_wait;
 980
 981                //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode);
 982
 983                /* Was opening raw or udp socket here
 984                 * if (listen_mode != LISTEN_NONE && sockfd < 0),
 985                 * but on fast network renew responses return faster
 986                 * than we open sockets. Thus this code is moved
 987                 * to change_listen_mode(). Thus we open listen socket
 988                 * BEFORE we send renew request (see "case BOUND:"). */
 989
 990                max_fd = udhcp_sp_fd_set(&rfds, sockfd);
 991
 992                tv.tv_sec = timeout - already_waited_sec;
 993                tv.tv_usec = 0;
 994                retval = 0;
 995                /* If we already timed out, fall through with retval = 0, else... */
 996                if ((int)tv.tv_sec > 0) {
 997                        timestamp_before_wait = (unsigned)monotonic_sec();
 998                        log1("Waiting on select...");
 999                        retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
1000                        if (retval < 0) {
1001                                /* EINTR? A signal was caught, don't panic */
1002                                if (errno == EINTR) {
1003                                        already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1004                                        continue;
1005                                }
1006                                /* Else: an error occured, panic! */
1007                                bb_perror_msg_and_die("select");
1008                        }
1009                }
1010
1011                /* If timeout dropped to zero, time to become active:
1012                 * resend discover/renew/whatever
1013                 */
1014                if (retval == 0) {
1015                        /* We will restart the wait in any case */
1016                        already_waited_sec = 0;
1017
1018                        switch (state) {
1019                        case INIT_SELECTING:
1020                                if (packet_num < discover_retries) {
1021                                        if (packet_num == 0)
1022                                                xid = random_xid();
1023                                        /* broadcast */
1024                                        send_discover(xid, requested_ip);
1025                                        timeout = discover_timeout;
1026                                        packet_num++;
1027                                        continue;
1028                                }
1029 leasefail:
1030                                udhcp_run_script(NULL, "leasefail");
1031#if BB_MMU /* -b is not supported on NOMMU */
1032                                if (opt & OPT_b) { /* background if no lease */
1033                                        bb_info_msg("No lease, forking to background");
1034                                        client_background();
1035                                        /* do not background again! */
1036                                        opt = ((opt & ~OPT_b) | OPT_f);
1037                                } else
1038#endif
1039                                if (opt & OPT_n) { /* abort if no lease */
1040                                        bb_info_msg("No lease, failing");
1041                                        retval = 1;
1042                                        goto ret;
1043                                }
1044                                /* wait before trying again */
1045                                timeout = tryagain_timeout;
1046                                packet_num = 0;
1047                                continue;
1048                        case REQUESTING:
1049                                if (packet_num < discover_retries) {
1050                                        /* send broadcast select packet */
1051                                        send_select(xid, server_addr, requested_ip);
1052                                        timeout = discover_timeout;
1053                                        packet_num++;
1054                                        continue;
1055                                }
1056                                /* Timed out, go back to init state.
1057                                 * "discover...select...discover..." loops
1058                                 * were seen in the wild. Treat them similarly
1059                                 * to "no response to discover" case */
1060                                change_listen_mode(LISTEN_RAW);
1061                                state = INIT_SELECTING;
1062                                goto leasefail;
1063                        case BOUND:
1064                                /* 1/2 lease passed, enter renewing state */
1065                                state = RENEWING;
1066                                change_listen_mode(LISTEN_KERNEL);
1067                                log1("Entering renew state");
1068                                /* fall right through */
1069                        case RENEW_REQUESTED: /* manual (SIGUSR1) renew */
1070                        case_RENEW_REQUESTED:
1071                        case RENEWING:
1072                                if (timeout > 60) {
1073                                        /* send an unicast renew request */
1074                        /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
1075                         * a new UDP socket for sending inside send_renew.
1076                         * I hazard to guess existing listening socket
1077                         * is somehow conflicting with it, but why is it
1078                         * not deterministic then?! Strange.
1079                         * Anyway, it does recover by eventually failing through
1080                         * into INIT_SELECTING state.
1081                         */
1082                                        send_renew(xid, server_addr, requested_ip);
1083                                        timeout >>= 1;
1084                                        continue;
1085                                }
1086                                /* Timed out, enter rebinding state */
1087                                log1("Entering rebinding state");
1088                                state = REBINDING;
1089                                /* fall right through */
1090                        case REBINDING:
1091                                /* Switch to bcast receive */
1092                                change_listen_mode(LISTEN_RAW);
1093                                /* Lease is *really* about to run out,
1094                                 * try to find DHCP server using broadcast */
1095                                if (timeout > 0) {
1096                                        /* send a broadcast renew request */
1097                                        send_renew(xid, 0 /*INADDR_ANY*/, requested_ip);
1098                                        timeout >>= 1;
1099                                        continue;
1100                                }
1101                                /* Timed out, enter init state */
1102                                bb_info_msg("Lease lost, entering init state");
1103                                udhcp_run_script(NULL, "deconfig");
1104                                state = INIT_SELECTING;
1105                                /*timeout = 0; - already is */
1106                                packet_num = 0;
1107                                continue;
1108                        /* case RELEASED: */
1109                        }
1110                        /* yah, I know, *you* say it would never happen */
1111                        timeout = INT_MAX;
1112                        continue; /* back to main loop */
1113                } /* if select timed out */
1114
1115                /* select() didn't timeout, something happened */
1116
1117                /* Is it a signal? */
1118                /* note: udhcp_sp_read checks FD_ISSET before reading */
1119                switch (udhcp_sp_read(&rfds)) {
1120                case SIGUSR1:
1121                        perform_renew();
1122                        if (state == RENEW_REQUESTED)
1123                                goto case_RENEW_REQUESTED;
1124                        /* Start things over */
1125                        packet_num = 0;
1126                        /* Kill any timeouts, user wants this to hurry along */
1127                        timeout = 0;
1128                        continue;
1129                case SIGUSR2:
1130                        perform_release(requested_ip, server_addr);
1131                        timeout = INT_MAX;
1132                        continue;
1133                case SIGTERM:
1134                        bb_info_msg("Received SIGTERM");
1135                        if (opt & OPT_R) /* release on quit */
1136                                perform_release(requested_ip, server_addr);
1137                        goto ret0;
1138                }
1139
1140                /* Is it a packet? */
1141                if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds))
1142                        continue; /* no */
1143
1144                {
1145                        int len;
1146
1147                        /* A packet is ready, read it */
1148                        if (listen_mode == LISTEN_KERNEL)
1149                                len = udhcp_recv_kernel_packet(&packet, sockfd);
1150                        else
1151                                len = udhcp_recv_raw_packet(&packet, sockfd);
1152                        if (len == -1) {
1153                                /* Error is severe, reopen socket */
1154                                bb_info_msg("Read error: %s, reopening socket", strerror(errno));
1155                                sleep(discover_timeout); /* 3 seconds by default */
1156                                change_listen_mode(listen_mode); /* just close and reopen */
1157                        }
1158                        /* If this packet will turn out to be unrelated/bogus,
1159                         * we will go back and wait for next one.
1160                         * Be sure timeout is properly decreased. */
1161                        already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1162                        if (len < 0)
1163                                continue;
1164                }
1165
1166                if (packet.xid != xid) {
1167                        log1("xid %x (our is %x), ignoring packet",
1168                                (unsigned)packet.xid, (unsigned)xid);
1169                        continue;
1170                }
1171
1172                /* Ignore packets that aren't for us */
1173                if (packet.hlen != 6
1174                 || memcmp(packet.chaddr, client_config.client_mac, 6)
1175                ) {
1176//FIXME: need to also check that last 10 bytes are zero
1177                        log1("chaddr does not match, ignoring packet"); // log2?
1178                        continue;
1179                }
1180
1181                message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
1182                if (message == NULL) {
1183                        bb_error_msg("no message type option, ignoring packet");
1184                        continue;
1185                }
1186
1187                switch (state) {
1188                case INIT_SELECTING:
1189                        /* Must be a DHCPOFFER to one of our xid's */
1190                        if (*message == DHCPOFFER) {
1191                /* TODO: why we don't just fetch server's IP from IP header? */
1192                                temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
1193                                if (!temp) {
1194                                        bb_error_msg("no server ID in message");
1195                                        continue;
1196                                        /* still selecting - this server looks bad */
1197                                }
1198                                /* it IS unaligned sometimes, don't "optimize" */
1199                                move_from_unaligned32(server_addr, temp);
1200                                xid = packet.xid;
1201                                requested_ip = packet.yiaddr;
1202
1203                                /* enter requesting state */
1204                                state = REQUESTING;
1205                                timeout = 0;
1206                                packet_num = 0;
1207                                already_waited_sec = 0;
1208                        }
1209                        continue;
1210                case REQUESTING:
1211                case RENEWING:
1212                case RENEW_REQUESTED:
1213                case REBINDING:
1214                        if (*message == DHCPACK) {
1215                                temp = udhcp_get_option(&packet, DHCP_LEASE_TIME);
1216                                if (!temp) {
1217                                        bb_error_msg("no lease time with ACK, using 1 hour lease");
1218                                        lease_seconds = 60 * 60;
1219                                } else {
1220                                        /* it IS unaligned sometimes, don't "optimize" */
1221                                        move_from_unaligned32(lease_seconds, temp);
1222                                        lease_seconds = ntohl(lease_seconds);
1223                                        lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */
1224                                        if (lease_seconds < 10) /* and not too small */
1225                                                lease_seconds = 10;
1226                                }
1227#if ENABLE_FEATURE_UDHCPC_ARPING
1228                                if (opt & OPT_a) {
1229/* RFC 2131 3.1 paragraph 5:
1230 * "The client receives the DHCPACK message with configuration
1231 * parameters. The client SHOULD perform a final check on the
1232 * parameters (e.g., ARP for allocated network address), and notes
1233 * the duration of the lease specified in the DHCPACK message. At this
1234 * point, the client is configured. If the client detects that the
1235 * address is already in use (e.g., through the use of ARP),
1236 * the client MUST send a DHCPDECLINE message to the server and restarts
1237 * the configuration process..." */
1238                                        if (!arpping(packet.yiaddr,
1239                                                        NULL,
1240                                                        (uint32_t) 0,
1241                                                        client_config.client_mac,
1242                                                        client_config.interface)
1243                                        ) {
1244                                                bb_info_msg("Offered address is in use "
1245                                                        "(got ARP reply), declining");
1246                                                send_decline(xid, server_addr, packet.yiaddr);
1247
1248                                                if (state != REQUESTING)
1249                                                        udhcp_run_script(NULL, "deconfig");
1250                                                change_listen_mode(LISTEN_RAW);
1251                                                state = INIT_SELECTING;
1252                                                requested_ip = 0;
1253                                                timeout = tryagain_timeout;
1254                                                packet_num = 0;
1255                                                already_waited_sec = 0;
1256                                                continue; /* back to main loop */
1257                                        }
1258                                }
1259#endif
1260                                /* enter bound state */
1261                                timeout = lease_seconds / 2;
1262                                {
1263                                        struct in_addr temp_addr;
1264                                        temp_addr.s_addr = packet.yiaddr;
1265                                        bb_info_msg("Lease of %s obtained, lease time %u",
1266                                                inet_ntoa(temp_addr), (unsigned)lease_seconds);
1267                                }
1268                                requested_ip = packet.yiaddr;
1269                                udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew");
1270
1271                                state = BOUND;
1272                                change_listen_mode(LISTEN_NONE);
1273                                if (opt & OPT_q) { /* quit after lease */
1274                                        if (opt & OPT_R) /* release on quit */
1275                                                perform_release(requested_ip, server_addr);
1276                                        goto ret0;
1277                                }
1278                                /* future renew failures should not exit (JM) */
1279                                opt &= ~OPT_n;
1280#if BB_MMU /* NOMMU case backgrounded earlier */
1281                                if (!(opt & OPT_f)) {
1282                                        client_background();
1283                                        /* do not background again! */
1284                                        opt = ((opt & ~OPT_b) | OPT_f);
1285                                }
1286#endif
1287                                already_waited_sec = 0;
1288                                continue; /* back to main loop */
1289                        }
1290                        if (*message == DHCPNAK) {
1291                                /* return to init state */
1292                                bb_info_msg("Received DHCP NAK");
1293                                udhcp_run_script(&packet, "nak");
1294                                if (state != REQUESTING)
1295                                        udhcp_run_script(NULL, "deconfig");
1296                                change_listen_mode(LISTEN_RAW);
1297                                sleep(3); /* avoid excessive network traffic */
1298                                state = INIT_SELECTING;
1299                                requested_ip = 0;
1300                                timeout = 0;
1301                                packet_num = 0;
1302                                already_waited_sec = 0;
1303                        }
1304                        continue;
1305                /* case BOUND: - ignore all packets */
1306                /* case RELEASED: - ignore all packets */
1307                }
1308                /* back to main loop */
1309        } /* for (;;) - main loop ends */
1310
1311 ret0:
1312        retval = 0;
1313 ret:
1314        /*if (client_config.pidfile) - remove_pidfile has its own check */
1315                remove_pidfile(client_config.pidfile);
1316        return retval;
1317}
1318