Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcpc.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* dhcpc.c
    3  *
    4  * udhcp DHCP client
     2/*
     3 * udhcp client
    54 *
    65 * Russ Dill <Russ.Dill@asu.edu> July 2001
    76 *
    8  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     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.
    920 */
    10 
    11 #include <getopt.h>
    1221#include <syslog.h>
    13 
    1422/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */
    1523#define WANT_PIDFILE 1
     
    1725#include "dhcpd.h"
    1826#include "dhcpc.h"
    19 #include "options.h"
    20 
    21 
    22 /* Something is definitely wrong here. IPv4 addresses
    23  * in variables of type long?? BTW, we use inet_ntoa()
    24  * in the code. Manpage says that struct in_addr has a member of type long (!)
    25  * which holds IPv4 address, and the struct is passed by value (!!)
     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
     93    type = optflag->flags & OPTION_TYPE_MASK;
     94    optlen = dhcp_option_lengths[type];
     95    upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen);
     96
     97    dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
     98    dest += sprintf(ret, "%s=", opt_name);
     99
     100    while (len >= optlen) {
     101        unsigned ip_ofs = 0;
     102
     103        switch (type) {
     104        case OPTION_IP_PAIR:
     105            dest += sprint_nip(dest, "", option);
     106            *dest++ = '/';
     107            ip_ofs = 4;
     108            /* fall through */
     109        case OPTION_IP:
     110            dest += sprint_nip(dest, "", option + ip_ofs);
     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// TODO: it can be a list only if (optflag->flags & OPTION_LIST).
     222// Should we bail out/warn if we see multi-ip option which is
     223// not allowed to be such (for example, DHCP_BROADCAST)? -
     224        if (len <= 0 /* || !(optflag->flags & OPTION_LIST) */)
     225            break;
     226        *dest++ = ' ';
     227        *dest = '\0';
     228    }
     229    return ret;
     230}
     231
     232/* put all the parameters into the environment */
     233static char **fill_envp(struct dhcp_packet *packet)
     234{
     235    int envc;
     236    int i;
     237    char **envp, **curr;
     238    const char *opt_name;
     239    uint8_t *temp;
     240    uint8_t overload = 0;
     241
     242    /* We need 6 elements for:
     243     * "interface=IFACE"
     244     * "ip=N.N.N.N" from packet->yiaddr
     245     * "siaddr=IP" from packet->siaddr_nip (unless 0)
     246     * "boot_file=FILE" from packet->file (unless overloaded)
     247     * "sname=SERVER_HOSTNAME" from packet->sname (unless overloaded)
     248     * terminating NULL
     249     */
     250    envc = 6;
     251    /* +1 element for each option, +2 for subnet option: */
     252    if (packet) {
     253        for (i = 0; dhcp_optflags[i].code; i++) {
     254            if (udhcp_get_option(packet, dhcp_optflags[i].code)) {
     255                if (dhcp_optflags[i].code == DHCP_SUBNET)
     256                    envc++; /* for mton */
     257                envc++;
     258            }
     259        }
     260        temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD);
     261        if (temp)
     262            overload = *temp;
     263    }
     264    curr = envp = xzalloc(sizeof(char *) * envc);
     265
     266    *curr = xasprintf("interface=%s", client_config.interface);
     267    putenv(*curr++);
     268
     269    if (!packet)
     270        return envp;
     271
     272    *curr = xmalloc(sizeof("ip=255.255.255.255"));
     273    sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr);
     274    putenv(*curr++);
     275
     276    opt_name = dhcp_option_strings;
     277    i = 0;
     278    while (*opt_name) {
     279        temp = udhcp_get_option(packet, dhcp_optflags[i].code);
     280        if (!temp)
     281            goto next;
     282        *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name);
     283        putenv(*curr++);
     284        if (dhcp_optflags[i].code == DHCP_SUBNET) {
     285            /* Subnet option: make things like "$ip/$mask" possible */
     286            uint32_t subnet;
     287            move_from_unaligned32(subnet, temp);
     288            *curr = xasprintf("mask=%d", mton(subnet));
     289            putenv(*curr++);
     290        }
     291 next:
     292        opt_name += strlen(opt_name) + 1;
     293        i++;
     294    }
     295    if (packet->siaddr_nip) {
     296        *curr = xmalloc(sizeof("siaddr=255.255.255.255"));
     297        sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip);
     298        putenv(*curr++);
     299    }
     300    if (!(overload & FILE_FIELD) && packet->file[0]) {
     301        /* watch out for invalid packets */
     302        *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file);
     303        putenv(*curr++);
     304    }
     305    if (!(overload & SNAME_FIELD) && packet->sname[0]) {
     306        /* watch out for invalid packets */
     307        *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
     308        putenv(*curr++);
     309    }
     310    return envp;
     311}
     312
     313/* Call a script with a par file and env vars */
     314static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
     315{
     316    char **envp, **curr;
     317    char *argv[3];
     318
     319    if (client_config.script == NULL)
     320        return;
     321
     322    envp = fill_envp(packet);
     323
     324    /* call script */
     325    log1("Executing %s %s", client_config.script, name);
     326    argv[0] = (char*) client_config.script;
     327    argv[1] = (char*) name;
     328    argv[2] = NULL;
     329    spawn_and_wait(argv);
     330
     331    for (curr = envp; *curr; curr++) {
     332        log2(" %s", *curr);
     333        bb_unsetenv_and_free(*curr);
     334    }
     335    free(envp);
     336}
     337
     338
     339/*** Sending/receiving packets ***/
     340
     341static ALWAYS_INLINE uint32_t random_xid(void)
     342{
     343    return rand();
     344}
     345
     346/* Initialize the packet with the proper defaults */
     347static void init_packet(struct dhcp_packet *packet, char type)
     348{
     349    /* Fill in: op, htype, hlen, cookie fields; message type option: */
     350    udhcp_init_header(packet, type);
     351
     352    packet->xid = random_xid();
     353
     354    memcpy(packet->chaddr, client_config.client_mac, 6);
     355    if (client_config.clientid)
     356        udhcp_add_binary_option(packet, client_config.clientid);
     357}
     358
     359static void add_client_options(struct dhcp_packet *packet)
     360{
     361    uint8_t c;
     362    int i, end, len;
     363
     364    udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE));
     365
     366    /* Add a "param req" option with the list of options we'd like to have
     367     * from stubborn DHCP servers. Pull the data from the struct in common.c.
     368     * No bounds checking because it goes towards the head of the packet. */
     369    end = udhcp_end_option(packet->options);
     370    len = 0;
     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    if (client_config.vendorclass)
     388        udhcp_add_binary_option(packet, client_config.vendorclass);
     389    if (client_config.hostname)
     390        udhcp_add_binary_option(packet, client_config.hostname);
     391    if (client_config.fqdn)
     392        udhcp_add_binary_option(packet, client_config.fqdn);
     393
     394    /* Add -x options if any */
     395    {
     396        struct option_set *curr = client_config.options;
     397        while (curr) {
     398            udhcp_add_binary_option(packet, curr->data);
     399            curr = curr->next;
     400        }
     401//      if (client_config.sname)
     402//          strncpy((char*)packet->sname, client_config.sname, sizeof(packet->sname) - 1);
     403//      if (client_config.boot_file)
     404//          strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1);
     405    }
     406}
     407
     408/* RFC 2131
     409 * 4.4.4 Use of broadcast and unicast
     410 *
     411 * The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM
     412 * messages, unless the client knows the address of a DHCP server.
     413 * The client unicasts DHCPRELEASE messages to the server. Because
     414 * the client is declining the use of the IP address supplied by the server,
     415 * the client broadcasts DHCPDECLINE messages.
     416 *
     417 * When the DHCP client knows the address of a DHCP server, in either
     418 * INIT or REBOOTING state, the client may use that address
     419 * in the DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address.
     420 * The client may also use unicast to send DHCPINFORM messages
     421 * to a known DHCP server. If the client receives no response to DHCP
     422 * messages sent to the IP address of a known DHCP server, the DHCP
     423 * client reverts to using the IP broadcast address.
    26424 */
    27 static unsigned timeout;
    28 static uint32_t requested_ip; /* = 0 */
    29 static uint32_t server_addr;
    30 static int packet_num; /* = 0 */
     425
     426static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet)
     427{
     428    return udhcp_send_raw_packet(packet,
     429        /*src*/ INADDR_ANY, CLIENT_PORT,
     430        /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
     431        client_config.ifindex);
     432}
     433
     434/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
     435/* NOINLINE: limit stack usage in caller */
     436static NOINLINE int send_discover(uint32_t xid, uint32_t requested)
     437{
     438    struct dhcp_packet packet;
     439
     440    /* Fill in: op, htype, hlen, cookie, chaddr fields,
     441     * random xid field (we override it below),
     442     * client-id option (unless -C), message type option:
     443     */
     444    init_packet(&packet, DHCPDISCOVER);
     445
     446    packet.xid = xid;
     447    if (requested)
     448        udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
     449
     450    /* Add options: maxsize,
     451     * optionally: hostname, fqdn, vendorclass,
     452     * "param req" option according to -O, options specified with -x
     453     */
     454    add_client_options(&packet);
     455
     456    bb_info_msg("Sending discover...");
     457    return raw_bcast_from_client_config_ifindex(&packet);
     458}
     459
     460/* Broadcast a DHCP request message */
     461/* RFC 2131 3.1 paragraph 3:
     462 * "The client _broadcasts_ a DHCPREQUEST message..."
     463 */
     464/* NOINLINE: limit stack usage in caller */
     465static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested)
     466{
     467    struct dhcp_packet packet;
     468    struct in_addr addr;
     469
     470/*
     471 * RFC 2131 4.3.2 DHCPREQUEST message
     472 * ...
     473 * If the DHCPREQUEST message contains a 'server identifier'
     474 * option, the message is in response to a DHCPOFFER message.
     475 * Otherwise, the message is a request to verify or extend an
     476 * existing lease. If the client uses a 'client identifier'
     477 * in a DHCPREQUEST message, it MUST use that same 'client identifier'
     478 * in all subsequent messages. If the client included a list
     479 * of requested parameters in a DHCPDISCOVER message, it MUST
     480 * include that list in all subsequent messages.
     481 */
     482    /* Fill in: op, htype, hlen, cookie, chaddr fields,
     483     * random xid field (we override it below),
     484     * client-id option (unless -C), message type option:
     485     */
     486    init_packet(&packet, DHCPREQUEST);
     487
     488    packet.xid = xid;
     489    udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
     490
     491    udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
     492
     493    /* Add options: maxsize,
     494     * optionally: hostname, fqdn, vendorclass,
     495     * "param req" option according to -O, and options specified with -x
     496     */
     497    add_client_options(&packet);
     498
     499    addr.s_addr = requested;
     500    bb_info_msg("Sending select for %s...", inet_ntoa(addr));
     501    return raw_bcast_from_client_config_ifindex(&packet);
     502}
     503
     504/* Unicast or broadcast a DHCP renew message */
     505/* NOINLINE: limit stack usage in caller */
     506static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
     507{
     508    struct dhcp_packet packet;
     509
     510/*
     511 * RFC 2131 4.3.2 DHCPREQUEST message
     512 * ...
     513 * DHCPREQUEST generated during RENEWING state:
     514 *
     515 * 'server identifier' MUST NOT be filled in, 'requested IP address'
     516 * option MUST NOT be filled in, 'ciaddr' MUST be filled in with
     517 * client's IP address. In this situation, the client is completely
     518 * configured, and is trying to extend its lease. This message will
     519 * be unicast, so no relay agents will be involved in its
     520 * transmission.  Because 'giaddr' is therefore not filled in, the
     521 * DHCP server will trust the value in 'ciaddr', and use it when
     522 * replying to the client.
     523 */
     524    /* Fill in: op, htype, hlen, cookie, chaddr fields,
     525     * random xid field (we override it below),
     526     * client-id option (unless -C), message type option:
     527     */
     528    init_packet(&packet, DHCPREQUEST);
     529
     530    packet.xid = xid;
     531    packet.ciaddr = ciaddr;
     532
     533    /* Add options: maxsize,
     534     * optionally: hostname, fqdn, vendorclass,
     535     * "param req" option according to -O, and options specified with -x
     536     */
     537    add_client_options(&packet);
     538
     539    bb_info_msg("Sending renew...");
     540    if (server)
     541        return udhcp_send_kernel_packet(&packet,
     542            ciaddr, CLIENT_PORT,
     543            server, SERVER_PORT);
     544    return raw_bcast_from_client_config_ifindex(&packet);
     545}
     546
     547#if ENABLE_FEATURE_UDHCPC_ARPING
     548/* Broadcast a DHCP decline message */
     549/* NOINLINE: limit stack usage in caller */
     550static NOINLINE int send_decline(uint32_t xid, uint32_t server, uint32_t requested)
     551{
     552    struct dhcp_packet packet;
     553
     554    /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
     555     * client-id option (unless -C), message type option:
     556     */
     557    init_packet(&packet, DHCPDECLINE);
     558
     559    /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client,
     560     * but in case the server is buggy and wants DHCPDECLINE's xid
     561     * to match the xid which started entire handshake,
     562     * we use the same xid we used in initial DHCPDISCOVER:
     563     */
     564    packet.xid = xid;
     565    /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */
     566    udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
     567
     568    udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
     569
     570    bb_info_msg("Sending decline...");
     571    return raw_bcast_from_client_config_ifindex(&packet);
     572}
     573#endif
     574
     575/* Unicast a DHCP release message */
     576static int send_release(uint32_t server, uint32_t ciaddr)
     577{
     578    struct dhcp_packet packet;
     579
     580    /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
     581     * client-id option (unless -C), message type option:
     582     */
     583    init_packet(&packet, DHCPRELEASE);
     584
     585    /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */
     586    packet.ciaddr = ciaddr;
     587
     588    udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
     589
     590    bb_info_msg("Sending release...");
     591    return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
     592}
     593
     594/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
     595/* NOINLINE: limit stack usage in caller */
     596static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
     597{
     598    int bytes;
     599    struct ip_udp_dhcp_packet packet;
     600    uint16_t check;
     601
     602    memset(&packet, 0, sizeof(packet));
     603    bytes = safe_read(fd, &packet, sizeof(packet));
     604    if (bytes < 0) {
     605        log1("Packet read error, ignoring");
     606        /* NB: possible down interface, etc. Caller should pause. */
     607        return bytes; /* returns -1 */
     608    }
     609
     610    if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) {
     611        log1("Packet is too short, ignoring");
     612        return -2;
     613    }
     614
     615    if (bytes < ntohs(packet.ip.tot_len)) {
     616        /* packet is bigger than sizeof(packet), we did partial read */
     617        log1("Oversized packet, ignoring");
     618        return -2;
     619    }
     620
     621    /* ignore any extra garbage bytes */
     622    bytes = ntohs(packet.ip.tot_len);
     623
     624    /* make sure its the right packet for us, and that it passes sanity checks */
     625    if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION
     626     || packet.ip.ihl != (sizeof(packet.ip) >> 2)
     627     || packet.udp.dest != htons(CLIENT_PORT)
     628    /* || bytes > (int) sizeof(packet) - can't happen */
     629     || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip))
     630    ) {
     631        log1("Unrelated/bogus packet, ignoring");
     632        return -2;
     633    }
     634
     635    /* verify IP checksum */
     636    check = packet.ip.check;
     637    packet.ip.check = 0;
     638    if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) {
     639        log1("Bad IP header checksum, ignoring");
     640        return -2;
     641    }
     642
     643    /* verify UDP checksum. IP header has to be modified for this */
     644    memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
     645    /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
     646    packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
     647    check = packet.udp.check;
     648    packet.udp.check = 0;
     649    if (check && check != udhcp_checksum(&packet, bytes)) {
     650        log1("Packet with bad UDP checksum received, ignoring");
     651        return -2;
     652    }
     653
     654    memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp)));
     655
     656    if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) {
     657        bb_info_msg("Packet with bad magic, ignoring");
     658        return -2;
     659    }
     660    log1("Got valid DHCP packet");
     661    udhcp_dump_packet(dhcp_pkt);
     662    return bytes - (sizeof(packet.ip) + sizeof(packet.udp));
     663}
     664
     665
     666/*** Main ***/
     667
    31668static int sockfd = -1;
    32669
    33 #define LISTEN_NONE 0
     670#define LISTEN_NONE   0
    34671#define LISTEN_KERNEL 1
    35 #define LISTEN_RAW 2
     672#define LISTEN_RAW    2
    36673static smallint listen_mode;
    37674
     675/* initial state: (re)start DHCP negotiation */
     676#define INIT_SELECTING  0
     677/* discover was sent, DHCPOFFER reply received */
     678#define REQUESTING      1
     679/* select/renew was sent, DHCPACK reply received */
     680#define BOUND           2
     681/* half of lease passed, want to renew it by sending unicast renew requests */
     682#define RENEWING        3
     683/* renew requests were not answered, lease is almost over, send broadcast renew */
     684#define REBINDING       4
     685/* manually requested renew (SIGUSR1) */
     686#define RENEW_REQUESTED 5
     687/* release, possibly manually requested (SIGUSR2) */
     688#define RELEASED        6
    38689static smallint state;
    39690
    40 struct client_config_t client_config;
    41 
    42 
    43 /* just a little helper */
    44 static void change_mode(int new_mode)
    45 {
    46     DEBUG("entering %s listen mode",
    47         new_mode ? (new_mode == 1 ? "kernel" : "raw") : "none");
     691static int udhcp_raw_socket(int ifindex)
     692{
     693    int fd;
     694    struct sockaddr_ll sock;
     695
     696    /*
     697     * Comment:
     698     *
     699     *  I've selected not to see LL header, so BPF doesn't see it, too.
     700     *  The filter may also pass non-IP and non-ARP packets, but we do
     701     *  a more complete check when receiving the message in userspace.
     702     *
     703     * and filter shamelessly stolen from:
     704     *
     705     *  http://www.flamewarmaster.de/software/dhcpclient/
     706     *
     707     * There are a few other interesting ideas on that page (look under
     708     * "Motivation").  Use of netlink events is most interesting.  Think
     709     * of various network servers listening for events and reconfiguring.
     710     * That would obsolete sending HUP signals and/or make use of restarts.
     711     *
     712     * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
     713     * License: GPL v2.
     714     *
     715     * TODO: make conditional?
     716     */
     717#define SERVER_AND_CLIENT_PORTS  ((67 << 16) + 68)
     718    static const struct sock_filter filter_instr[] = {
     719        /* check for udp */
     720        BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
     721        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0),     /* L5, L1, is UDP? */
     722        /* ugly check for arp on ethernet-like and IPv4 */
     723        BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),                      /* L1: */
     724        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4),      /* L3, L4 */
     725        /* skip IP header */
     726        BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),                     /* L5: */
     727        /* check udp source and destination ports */
     728        BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0),
     729        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */
     730        /* returns */
     731        BPF_STMT(BPF_RET|BPF_K, 0x0fffffff ),                   /* L3: pass */
     732        BPF_STMT(BPF_RET|BPF_K, 0),                             /* L4: reject */
     733    };
     734    static const struct sock_fprog filter_prog = {
     735        .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
     736        /* casting const away: */
     737        .filter = (struct sock_filter *) filter_instr,
     738    };
     739
     740    log1("Opening raw socket on ifindex %d", ifindex); //log2?
     741
     742    fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
     743    log1("Got raw socket fd %d", fd); //log2?
     744
     745    if (SERVER_PORT == 67 && CLIENT_PORT == 68) {
     746        /* Use only if standard ports are in use */
     747        /* Ignoring error (kernel may lack support for this) */
     748        if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
     749                sizeof(filter_prog)) >= 0)
     750            log1("Attached filter to raw socket fd %d", fd); // log?
     751    }
     752
     753    sock.sll_family = AF_PACKET;
     754    sock.sll_protocol = htons(ETH_P_IP);
     755    sock.sll_ifindex = ifindex;
     756    xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
     757    log1("Created raw socket");
     758
     759    return fd;
     760}
     761
     762static void change_listen_mode(int new_mode)
     763{
     764    log1("Entering listen mode: %s",
     765        new_mode != LISTEN_NONE
     766            ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
     767            : "none"
     768    );
     769
     770    listen_mode = new_mode;
    48771    if (sockfd >= 0) {
    49772        close(sockfd);
    50773        sockfd = -1;
    51774    }
    52     listen_mode = new_mode;
    53 }
    54 
    55 
    56 /* perform a renew */
     775    if (new_mode == LISTEN_KERNEL)
     776        sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
     777    else if (new_mode != LISTEN_NONE)
     778        sockfd = udhcp_raw_socket(client_config.ifindex);
     779    /* else LISTEN_NONE: sockfd stays closed */
     780}
     781
    57782static void perform_renew(void)
    58783{
     
    60785    switch (state) {
    61786    case BOUND:
    62         change_mode(LISTEN_KERNEL);
     787        change_listen_mode(LISTEN_KERNEL);
    63788    case RENEWING:
    64789    case REBINDING:
     
    69794    case REQUESTING:
    70795    case RELEASED:
    71         change_mode(LISTEN_RAW);
     796        change_listen_mode(LISTEN_RAW);
    72797        state = INIT_SELECTING;
    73798        break;
     
    75800        break;
    76801    }
    77 
    78     /* start things over */
    79     packet_num = 0;
    80 
    81     /* Kill any timeouts because the user wants this to hurry along */
    82     timeout = 0;
    83 }
    84 
    85 
    86 /* perform a release */
    87 static void perform_release(void)
     802}
     803
     804static void perform_release(uint32_t requested_ip, uint32_t server_addr)
    88805{
    89806    char buffer[sizeof("255.255.255.255")];
     
    102819    bb_info_msg("Entering released state");
    103820
    104     change_mode(LISTEN_NONE);
     821    change_listen_mode(LISTEN_NONE);
    105822    state = RELEASED;
    106     timeout = INT_MAX;
    107 }
    108 
    109 
    110 static void client_background(void)
    111 {
    112 #if !BB_MMU
    113     bb_error_msg("cannot background in uclinux (yet)");
    114 /* ... mainly because udhcpc calls client_background()
    115  * in _the _middle _of _udhcpc _run_, not at the start!
    116  * If that will be properly disabled for NOMMU, client_background()
    117  * will work on NOMMU too */
    118 #else
    119     bb_daemonize(0);
    120     logmode &= ~LOGMODE_STDIO;
    121     /* rewrite pidfile, as our pid is different now */
    122     write_pidfile(client_config.pidfile);
    123 #endif
    124     /* Do not fork again. */
    125     client_config.foreground = 1;
    126     client_config.background_if_no_lease = 0;
    127 }
    128 
     823}
    129824
    130825static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
    131826{
    132827    uint8_t *storage;
    133     int len = strlen(str);
    134     if (len > 255) len = 255;
     828    int len = strnlen(str, 255);
    135829    storage = xzalloc(len + extra + OPT_DATA);
    136830    storage[OPT_CODE] = code;
     
    140834}
    141835
    142 
    143 int udhcpc_main(int argc, char **argv);
    144 int udhcpc_main(int argc, char **argv)
     836#if BB_MMU
     837static void client_background(void)
     838{
     839    bb_daemonize(0);
     840    logmode &= ~LOGMODE_STDIO;
     841    /* rewrite pidfile, as our pid is different now */
     842    write_pidfile(client_config.pidfile);
     843}
     844#endif
     845
     846//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     847//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
     848//usage:#else
     849//usage:# define IF_UDHCP_VERBOSE(...)
     850//usage:#endif
     851//usage:#define udhcpc_trivial_usage
     852//usage:       "[-fbnq"IF_UDHCP_VERBOSE("v")"oCR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
     853//usage:       "    [-H HOSTNAME] [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
     854//usage:#define udhcpc_full_usage "\n"
     855//usage:    IF_LONG_OPTS(
     856//usage:     "\n    -i,--interface IFACE    Interface to use (default eth0)"
     857//usage:     "\n    -p,--pidfile FILE   Create pidfile"
     858//usage:     "\n    -s,--script PROG    Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
     859//usage:     "\n    -t,--retries N      Send up to N discover packets"
     860//usage:     "\n    -T,--timeout N      Pause between packets (default 3 seconds)"
     861//usage:     "\n    -A,--tryagain N     Wait N seconds after failure (default 20)"
     862//usage:     "\n    -f,--foreground     Run in foreground"
     863//usage:    USE_FOR_MMU(
     864//usage:     "\n    -b,--background     Background if lease is not obtained"
     865//usage:    )
     866//usage:     "\n    -n,--now        Exit if lease is not obtained"
     867//usage:     "\n    -q,--quit       Exit after obtaining lease"
     868//usage:     "\n    -R,--release        Release IP on exit"
     869//usage:     "\n    -S,--syslog     Log to syslog too"
     870//usage:    IF_FEATURE_UDHCP_PORT(
     871//usage:     "\n    -P,--client-port N  Use port N (default 68)"
     872//usage:    )
     873//usage:    IF_FEATURE_UDHCPC_ARPING(
     874//usage:     "\n    -a,--arping     Use arping to validate offered address"
     875//usage:    )
     876//usage:     "\n    -O,--request-option OPT Request option OPT from server (cumulative)"
     877//usage:     "\n    -o,--no-default-options Don't request any options (unless -O is given)"
     878//usage:     "\n    -r,--request IP     Request this IP address"
     879//usage:     "\n    -x OPT:VAL      Include option OPT in sent packets (cumulative)"
     880//usage:     "\n                Examples of string, numeric, and hex byte opts:"
     881//usage:     "\n                -x hostname:bbox - option 12"
     882//usage:     "\n                -x lease:3600 - option 51 (lease time)"
     883//usage:     "\n                -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
     884//usage:     "\n    -F,--fqdn NAME      Ask server to update DNS mapping for NAME"
     885//usage:     "\n    -H,-h,--hostname NAME   Send NAME as client hostname (default none)"
     886//usage:     "\n    -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')"
     887//usage:     "\n    -C,--clientid-none  Don't send MAC as client identifier"
     888//usage:    IF_UDHCP_VERBOSE(
     889//usage:     "\n    -v          Verbose"
     890//usage:    )
     891//usage:    )
     892//usage:    IF_NOT_LONG_OPTS(
     893//usage:     "\n    -i IFACE    Interface to use (default eth0)"
     894//usage:     "\n    -p FILE     Create pidfile"
     895//usage:     "\n    -s PROG     Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
     896//usage:     "\n    -t N        Send up to N discover packets"
     897//usage:     "\n    -T N        Pause between packets (default 3 seconds)"
     898//usage:     "\n    -A N        Wait N seconds (default 20) after failure"
     899//usage:     "\n    -f      Run in foreground"
     900//usage:    USE_FOR_MMU(
     901//usage:     "\n    -b      Background if lease is not obtained"
     902//usage:    )
     903//usage:     "\n    -n      Exit if lease is not obtained"
     904//usage:     "\n    -q      Exit after obtaining lease"
     905//usage:     "\n    -R      Release IP on exit"
     906//usage:     "\n    -S      Log to syslog too"
     907//usage:    IF_FEATURE_UDHCP_PORT(
     908//usage:     "\n    -P N        Use port N (default 68)"
     909//usage:    )
     910//usage:    IF_FEATURE_UDHCPC_ARPING(
     911//usage:     "\n    -a      Use arping to validate offered address"
     912//usage:    )
     913//usage:     "\n    -O OPT      Request option OPT from server (cumulative)"
     914//usage:     "\n    -o      Don't request any options (unless -O is given)"
     915//usage:     "\n    -r IP       Request this IP address"
     916//usage:     "\n    -x OPT:VAL  Include option OPT in sent packets (cumulative)"
     917//usage:     "\n            Examples of string, numeric, and hex byte opts:"
     918//usage:     "\n            -x hostname:bbox - option 12"
     919//usage:     "\n            -x lease:3600 - option 51 (lease time)"
     920//usage:     "\n            -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
     921//usage:     "\n    -F NAME     Ask server to update DNS mapping for NAME"
     922//usage:     "\n    -H,-h NAME  Send NAME as client hostname (default none)"
     923//usage:     "\n    -V VENDOR   Vendor identifier (default 'udhcp VERSION')"
     924//usage:     "\n    -C      Don't send MAC as client identifier"
     925//usage:    IF_UDHCP_VERBOSE(
     926//usage:     "\n    -v      Verbose"
     927//usage:    )
     928//usage:    )
     929
     930int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     931int udhcpc_main(int argc UNUSED_PARAM, char **argv)
    145932{
    146933    uint8_t *temp, *message;
    147     char *str_c, *str_V, *str_h, *str_F, *str_r, *str_T, *str_t;
     934    const char *str_V, *str_h, *str_F, *str_r;
     935    IF_FEATURE_UDHCP_PORT(char *str_P;)
     936    void *clientid_mac_ptr;
     937    llist_t *list_O = NULL;
     938    llist_t *list_x = NULL;
     939    int tryagain_timeout = 20;
     940    int discover_timeout = 3;
     941    int discover_retries = 3;
     942    uint32_t server_addr = server_addr; /* for compiler */
     943    uint32_t requested_ip = 0;
    148944    uint32_t xid = 0;
    149     uint32_t lease = 0; /* can be given as 32-bit quantity */
    150     unsigned t1 = 0, t2 = 0; /* what a wonderful names */
    151     unsigned start = 0;
    152     unsigned now;
     945    uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */
     946    int packet_num;
     947    int timeout; /* must be signed */
     948    unsigned already_waited_sec;
    153949    unsigned opt;
    154950    int max_fd;
    155951    int retval;
    156     int len;
    157952    struct timeval tv;
    158     struct in_addr temp_addr;
    159     struct dhcpMessage packet;
     953    struct dhcp_packet packet;
    160954    fd_set rfds;
    161955
    162     enum {
    163         OPT_c = 1 << 0,
    164         OPT_C = 1 << 1,
    165         OPT_V = 1 << 2,
    166         OPT_f = 1 << 3,
    167         OPT_b = 1 << 4,
    168         OPT_H = 1 << 5,
    169         OPT_h = 1 << 6,
    170         OPT_F = 1 << 7,
    171         OPT_i = 1 << 8,
    172         OPT_n = 1 << 9,
    173         OPT_p = 1 << 10,
    174         OPT_q = 1 << 11,
    175         OPT_R = 1 << 12,
    176         OPT_r = 1 << 13,
    177         OPT_s = 1 << 14,
    178         OPT_T = 1 << 15,
    179         OPT_t = 1 << 16,
    180         OPT_v = 1 << 17,
    181         OPT_S = 1 << 18,
    182     };
    183 #if ENABLE_GETOPT_LONG
     956#if ENABLE_LONG_OPTS
    184957    static const char udhcpc_longopts[] ALIGN1 =
    185         "clientid\0"      Required_argument "c"
    186         "clientid-none\0" No_argument       "C"
    187         "vendorclass\0"   Required_argument "V"
    188         "foreground\0"    No_argument       "f"
    189         "background\0"    No_argument       "b"
    190         "hostname\0"      Required_argument "H"
    191         "hostname\0"      Required_argument "h"
    192         "fqdn\0"          Required_argument "F"
    193         "interface\0"     Required_argument "i"
    194         "now\0"           No_argument       "n"
    195         "pidfile\0"       Required_argument "p"
    196         "quit\0"          No_argument       "q"
    197         "release\0"       No_argument       "R"
    198         "request\0"       Required_argument "r"
    199         "script\0"        Required_argument "s"
    200         "timeout\0"       Required_argument "T"
    201         "version\0"       No_argument       "v"
    202         "retries\0"       Required_argument "t"
    203         "syslog\0"        No_argument       "S"
     958        "clientid-none\0"  No_argument       "C"
     959        "vendorclass\0"    Required_argument "V"
     960        "hostname\0"       Required_argument "H"
     961        "fqdn\0"           Required_argument "F"
     962        "interface\0"      Required_argument "i"
     963        "now\0"            No_argument       "n"
     964        "pidfile\0"        Required_argument "p"
     965        "quit\0"           No_argument       "q"
     966        "release\0"        No_argument       "R"
     967        "request\0"        Required_argument "r"
     968        "script\0"         Required_argument "s"
     969        "timeout\0"        Required_argument "T"
     970        "version\0"        No_argument       "v"
     971        "retries\0"        Required_argument "t"
     972        "tryagain\0"       Required_argument "A"
     973        "syslog\0"         No_argument       "S"
     974        "request-option\0" Required_argument "O"
     975        "no-default-options\0" No_argument   "o"
     976        "foreground\0"     No_argument       "f"
     977        "background\0"     No_argument       "b"
     978        IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument       "a")
     979        IF_FEATURE_UDHCP_PORT("client-port\0"   Required_argument "P")
    204980        ;
    205981#endif
    206     /* Default options. */
     982    enum {
     983        OPT_C = 1 << 0,
     984        OPT_V = 1 << 1,
     985        OPT_H = 1 << 2,
     986        OPT_h = 1 << 3,
     987        OPT_F = 1 << 4,
     988        OPT_i = 1 << 5,
     989        OPT_n = 1 << 6,
     990        OPT_p = 1 << 7,
     991        OPT_q = 1 << 8,
     992        OPT_R = 1 << 9,
     993        OPT_r = 1 << 10,
     994        OPT_s = 1 << 11,
     995        OPT_T = 1 << 12,
     996        OPT_t = 1 << 13,
     997        OPT_S = 1 << 14,
     998        OPT_A = 1 << 15,
     999        OPT_O = 1 << 16,
     1000        OPT_o = 1 << 17,
     1001        OPT_x = 1 << 18,
     1002        OPT_f = 1 << 19,
     1003/* The rest has variable bit positions, need to be clever */
     1004        OPTBIT_f = 19,
     1005        USE_FOR_MMU(             OPTBIT_b,)
     1006        IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
     1007        IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
     1008        USE_FOR_MMU(             OPT_b = 1 << OPTBIT_b,)
     1009        IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
     1010        IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
     1011    };
     1012
     1013    /* Default options */
     1014    IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
     1015    IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
    2071016    client_config.interface = "eth0";
    208     client_config.script = DEFAULT_SCRIPT;
    209     client_config.retries = 3;
    210     client_config.timeout = 3;
     1017    client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
     1018    str_V = "udhcp "BB_VER;
    2111019
    2121020    /* Parse command line */
    213     opt_complementary = "c--C:C--c" // mutually exclusive
    214                         ":hH:Hh"; // -h and -H are the same
    215 #if ENABLE_GETOPT_LONG
    216     applet_long_options = udhcpc_longopts;
     1021    /* O,x: list; -T,-t,-A take numeric param */
     1022    opt_complementary = "O::x::T+:t+:A+"
     1023#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     1024        ":vv"
    2171025#endif
    218     opt = getopt32(argv, "c:CV:fbH:h:F:i:np:qRr:s:T:t:vS",
    219         &str_c, &str_V, &str_h, &str_h, &str_F,
    220         &client_config.interface, &client_config.pidfile, &str_r,
    221         &client_config.script, &str_T, &str_t
     1026        ;
     1027    IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
     1028    opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f"
     1029        USE_FOR_MMU("b")
     1030        IF_FEATURE_UDHCPC_ARPING("a")
     1031        IF_FEATURE_UDHCP_PORT("P:")
     1032        "v"
     1033        , &str_V, &str_h, &str_h, &str_F
     1034        , &client_config.interface, &client_config.pidfile, &str_r /* i,p */
     1035        , &client_config.script /* s */
     1036        , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
     1037        , &list_O
     1038        , &list_x
     1039        IF_FEATURE_UDHCP_PORT(, &str_P)
     1040#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     1041        , &dhcp_verbose
     1042#endif
    2221043        );
    223 
    224     if (opt & OPT_c)
    225         client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0);
    226     //if (opt & OPT_C)
    227     if (opt & OPT_V)
    228         client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
    229     if (opt & OPT_f)
    230         client_config.foreground = 1;
    231     if (opt & OPT_b)
    232         client_config.background_if_no_lease = 1;
    233     if (opt & OPT_h)
     1044    if (opt & (OPT_h|OPT_H))
    2341045        client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
    2351046    if (opt & OPT_F) {
     1047        /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */
    2361048        client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
    237         /* Flags: 0000NEOS
    238         S: 1 => Client requests Server to update A RR in DNS as well as PTR
    239         O: 1 => Server indicates to client that DNS has been updated regardless
    240         E: 1 => Name data is DNS format, i.e. <4>host<6>domain<4>com<0> not "host.domain.com"
    241         N: 1 => Client requests Server to not update DNS
    242         */
     1049        /* Flag bits: 0000NEOS
     1050         * S: 1 = Client requests server to update A RR in DNS as well as PTR
     1051         * O: 1 = Server indicates to client that DNS has been updated regardless
     1052         * E: 1 = Name is in DNS format, i.e. <4>host<6>domain<3>com<0>,
     1053         *    not "host.domain.com". Format 0 is obsolete.
     1054         * N: 1 = Client requests server to not update DNS (S must be 0 then)
     1055         * Two [0] bytes which follow are deprecated and must be 0.
     1056         */
    2431057        client_config.fqdn[OPT_DATA + 0] = 0x1;
    244         /* client_config.fqdn[OPT_DATA + 1] = 0; - redundant */
    245         /* client_config.fqdn[OPT_DATA + 2] = 0; - redundant */
    246     }
    247     // if (opt & OPT_i) client_config.interface = ...
    248     if (opt & OPT_n)
    249         client_config.abort_if_no_lease = 1;
    250     // if (opt & OPT_p) client_config.pidfile = ...
    251     if (opt & OPT_q)
    252         client_config.quit_after_lease = 1;
    253     if (opt & OPT_R)
    254         client_config.release_on_quit = 1;
     1058        /*client_config.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */
     1059        /*client_config.fqdn[OPT_DATA + 2] = 0; */
     1060    }
    2551061    if (opt & OPT_r)
    2561062        requested_ip = inet_addr(str_r);
    257     // if (opt & OPT_s) client_config.script = ...
    258     if (opt & OPT_T)
    259         client_config.timeout = xatoi_u(str_T);
    260     if (opt & OPT_t)
    261         client_config.retries = xatoi_u(str_t);
    262     if (opt & OPT_v) {
    263         printf("version %s\n", BB_VER);
    264         return 0;
    265     }
    266 
     1063#if ENABLE_FEATURE_UDHCP_PORT
     1064    if (opt & OPT_P) {
     1065        CLIENT_PORT = xatou16(str_P);
     1066        SERVER_PORT = CLIENT_PORT - 1;
     1067    }
     1068#endif
     1069    if (opt & OPT_o)
     1070        client_config.no_default_options = 1;
     1071    while (list_O) {
     1072        char *optstr = llist_pop(&list_O);
     1073        unsigned n = udhcp_option_idx(optstr);
     1074        n = dhcp_optflags[n].code;
     1075        client_config.opt_mask[n >> 3] |= 1 << (n & 7);
     1076    }
     1077    while (list_x) {
     1078        char *optstr = llist_pop(&list_x);
     1079        char *colon = strchr(optstr, ':');
     1080        if (colon)
     1081            *colon = ' ';
     1082        /* now it looks similar to udhcpd's config file line:
     1083         * "optname optval", using the common routine: */
     1084        udhcp_str2optset(optstr, &client_config.options);
     1085    }
     1086
     1087    if (udhcp_read_interface(client_config.interface,
     1088            &client_config.ifindex,
     1089            NULL,
     1090            client_config.client_mac)
     1091    ) {
     1092        return 1;
     1093    }
     1094
     1095    clientid_mac_ptr = NULL;
     1096    if (!(opt & OPT_C) && !udhcp_find_option(client_config.options, DHCP_CLIENT_ID)) {
     1097        /* not suppressed and not set, set the default client ID */
     1098        client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
     1099        client_config.clientid[OPT_DATA] = 1; /* type: ethernet */
     1100        clientid_mac_ptr = client_config.clientid + OPT_DATA+1;
     1101        memcpy(clientid_mac_ptr, client_config.client_mac, 6);
     1102    }
     1103    if (str_V[0] != '\0')
     1104        client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
     1105#if !BB_MMU
     1106    /* on NOMMU reexec (i.e., background) early */
     1107    if (!(opt & OPT_f)) {
     1108        bb_daemonize_or_rexec(0 /* flags */, argv);
     1109        logmode = LOGMODE_NONE;
     1110    }
     1111#endif
    2671112    if (opt & OPT_S) {
    268         openlog(applet_name, LOG_PID, LOG_LOCAL0);
     1113        openlog(applet_name, LOG_PID, LOG_DAEMON);
    2691114        logmode |= LOGMODE_SYSLOG;
    2701115    }
    271 
    272     if (read_interface(client_config.interface, &client_config.ifindex,
    273                NULL, client_config.arp))
    274         return 1;
    2751116
    2761117    /* Make sure fd 0,1,2 are open */
     
    2781119    /* Equivalent of doing a fflush after every \n */
    2791120    setlinebuf(stdout);
    280 
    2811121    /* Create pidfile */
    2821122    write_pidfile(client_config.pidfile);
    283     /* if (!..) bb_perror_msg("cannot create pidfile %s", pidfile); */
    284 
    285     /* Goes to stdout and possibly syslog */
    286     bb_info_msg("%s (v%s) started", applet_name, BB_VER);
    287 
    288     /* if not set, and not suppressed, setup the default client ID */
    289     if (!client_config.clientid && !(opt & OPT_C)) {
    290         client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
    291         client_config.clientid[OPT_DATA] = 1;
    292         memcpy(client_config.clientid + OPT_DATA+1, client_config.arp, 6);
    293     }
    294 
    295     if (!client_config.vendorclass)
    296         client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, "udhcp "BB_VER, 0);
    297 
    298     /* setup the signal pipe */
     1123    /* Goes to stdout (unless NOMMU) and possibly syslog */
     1124    bb_info_msg("%s (v"BB_VER") started", applet_name);
     1125    /* Set up the signal pipe */
    2991126    udhcp_sp_setup();
     1127    /* We want random_xid to be random... */
     1128    srand(monotonic_us());
    3001129
    3011130    state = INIT_SELECTING;
    3021131    udhcp_run_script(NULL, "deconfig");
    303     change_mode(LISTEN_RAW);
    304     tv.tv_sec = 0;
    305     goto jump_in;
    306 
     1132    change_listen_mode(LISTEN_RAW);
     1133    packet_num = 0;
     1134    timeout = 0;
     1135    already_waited_sec = 0;
     1136
     1137    /* Main event loop. select() waits on signal pipe and possibly
     1138     * on sockfd.
     1139     * "continue" statements in code below jump to the top of the loop.
     1140     */
    3071141    for (;;) {
    308         tv.tv_sec = timeout - monotonic_sec();
    309  jump_in:
     1142        /* silence "uninitialized!" warning */
     1143        unsigned timestamp_before_wait = timestamp_before_wait;
     1144
     1145        //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode);
     1146
     1147        /* Was opening raw or udp socket here
     1148         * if (listen_mode != LISTEN_NONE && sockfd < 0),
     1149         * but on fast network renew responses return faster
     1150         * than we open sockets. Thus this code is moved
     1151         * to change_listen_mode(). Thus we open listen socket
     1152         * BEFORE we send renew request (see "case BOUND:"). */
     1153
     1154        max_fd = udhcp_sp_fd_set(&rfds, sockfd);
     1155
     1156        tv.tv_sec = timeout - already_waited_sec;
    3101157        tv.tv_usec = 0;
    311 
    312         if (listen_mode != LISTEN_NONE && sockfd < 0) {
    313             if (listen_mode == LISTEN_KERNEL)
    314                 sockfd = listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
    315             else
    316                 sockfd = raw_socket(client_config.ifindex);
    317         }
    318         max_fd = udhcp_sp_fd_set(&rfds, sockfd);
    319 
    320         retval = 0; /* If we already timed out, fall through, else... */
    321         if (tv.tv_sec > 0) {
    322             DEBUG("Waiting on select...");
     1158        retval = 0;
     1159        /* If we already timed out, fall through with retval = 0, else... */
     1160        if ((int)tv.tv_sec > 0) {
     1161            timestamp_before_wait = (unsigned)monotonic_sec();
     1162            log1("Waiting on select...");
    3231163            retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
    324         }
    325 
    326         now = monotonic_sec();
    327         if (retval < 0) {
    328             /* EINTR? signal was caught, don't panic */
    329             if (errno != EINTR) {
     1164            if (retval < 0) {
     1165                /* EINTR? A signal was caught, don't panic */
     1166                if (errno == EINTR) {
     1167                    already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
     1168                    continue;
     1169                }
    3301170                /* Else: an error occured, panic! */
    3311171                bb_perror_msg_and_die("select");
    3321172            }
    333         } else if (retval == 0) {
    334             /* timeout dropped to zero */
     1173        }
     1174
     1175        /* If timeout dropped to zero, time to become active:
     1176         * resend discover/renew/whatever
     1177         */
     1178        if (retval == 0) {
     1179            /* When running on a bridge, the ifindex may have changed
     1180             * (e.g. if member interfaces were added/removed
     1181             * or if the status of the bridge changed).
     1182             * Refresh ifindex and client_mac:
     1183             */
     1184            if (udhcp_read_interface(client_config.interface,
     1185                    &client_config.ifindex,
     1186                    NULL,
     1187                    client_config.client_mac)
     1188            ) {
     1189                return 1; /* iface is gone? */
     1190            }
     1191            if (clientid_mac_ptr)
     1192                memcpy(clientid_mac_ptr, client_config.client_mac, 6);
     1193
     1194            /* We will restart the wait in any case */
     1195            already_waited_sec = 0;
     1196
    3351197            switch (state) {
    3361198            case INIT_SELECTING:
    337                 if (packet_num < client_config.retries) {
     1199                if (packet_num < discover_retries) {
    3381200                    if (packet_num == 0)
    3391201                        xid = random_xid();
    340 
    341                     /* send discover packet */
    342                     send_discover(xid, requested_ip); /* broadcast */
    343 
    344                     timeout = now + client_config.timeout;
     1202                    /* broadcast */
     1203                    send_discover(xid, requested_ip);
     1204                    timeout = discover_timeout;
    3451205                    packet_num++;
     1206                    continue;
     1207                }
     1208 leasefail:
     1209                udhcp_run_script(NULL, "leasefail");
     1210#if BB_MMU /* -b is not supported on NOMMU */
     1211                if (opt & OPT_b) { /* background if no lease */
     1212                    bb_info_msg("No lease, forking to background");
     1213                    client_background();
     1214                    /* do not background again! */
     1215                    opt = ((opt & ~OPT_b) | OPT_f);
     1216                } else
     1217#endif
     1218                if (opt & OPT_n) { /* abort if no lease */
     1219                    bb_info_msg("No lease, failing");
     1220                    retval = 1;
     1221                    goto ret;
     1222                }
     1223                /* wait before trying again */
     1224                timeout = tryagain_timeout;
     1225                packet_num = 0;
     1226                continue;
     1227            case REQUESTING:
     1228                if (packet_num < discover_retries) {
     1229                    /* send broadcast select packet */
     1230                    send_select(xid, server_addr, requested_ip);
     1231                    timeout = discover_timeout;
     1232                    packet_num++;
     1233                    continue;
     1234                }
     1235                /* Timed out, go back to init state.
     1236                 * "discover...select...discover..." loops
     1237                 * were seen in the wild. Treat them similarly
     1238                 * to "no response to discover" case */
     1239                change_listen_mode(LISTEN_RAW);
     1240                state = INIT_SELECTING;
     1241                goto leasefail;
     1242            case BOUND:
     1243                /* 1/2 lease passed, enter renewing state */
     1244                state = RENEWING;
     1245                change_listen_mode(LISTEN_KERNEL);
     1246                log1("Entering renew state");
     1247                /* fall right through */
     1248            case RENEW_REQUESTED: /* manual (SIGUSR1) renew */
     1249            case_RENEW_REQUESTED:
     1250            case RENEWING:
     1251                if (timeout > 60) {
     1252                    /* send an unicast renew request */
     1253            /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
     1254             * a new UDP socket for sending inside send_renew.
     1255             * I hazard to guess existing listening socket
     1256             * is somehow conflicting with it, but why is it
     1257             * not deterministic then?! Strange.
     1258             * Anyway, it does recover by eventually failing through
     1259             * into INIT_SELECTING state.
     1260             */
     1261                    send_renew(xid, server_addr, requested_ip);
     1262                    timeout >>= 1;
     1263                    continue;
     1264                }
     1265                /* Timed out, enter rebinding state */
     1266                log1("Entering rebinding state");
     1267                state = REBINDING;
     1268                /* fall right through */
     1269            case REBINDING:
     1270                /* Switch to bcast receive */
     1271                change_listen_mode(LISTEN_RAW);
     1272                /* Lease is *really* about to run out,
     1273                 * try to find DHCP server using broadcast */
     1274                if (timeout > 0) {
     1275                    /* send a broadcast renew request */
     1276                    send_renew(xid, 0 /*INADDR_ANY*/, requested_ip);
     1277                    timeout >>= 1;
     1278                    continue;
     1279                }
     1280                /* Timed out, enter init state */
     1281                bb_info_msg("Lease lost, entering init state");
     1282                udhcp_run_script(NULL, "deconfig");
     1283                state = INIT_SELECTING;
     1284                /*timeout = 0; - already is */
     1285                packet_num = 0;
     1286                continue;
     1287            /* case RELEASED: */
     1288            }
     1289            /* yah, I know, *you* say it would never happen */
     1290            timeout = INT_MAX;
     1291            continue; /* back to main loop */
     1292        } /* if select timed out */
     1293
     1294        /* select() didn't timeout, something happened */
     1295
     1296        /* Is it a signal? */
     1297        /* note: udhcp_sp_read checks FD_ISSET before reading */
     1298        switch (udhcp_sp_read(&rfds)) {
     1299        case SIGUSR1:
     1300            perform_renew();
     1301            if (state == RENEW_REQUESTED)
     1302                goto case_RENEW_REQUESTED;
     1303            /* Start things over */
     1304            packet_num = 0;
     1305            /* Kill any timeouts, user wants this to hurry along */
     1306            timeout = 0;
     1307            continue;
     1308        case SIGUSR2:
     1309            perform_release(requested_ip, server_addr);
     1310            timeout = INT_MAX;
     1311            continue;
     1312        case SIGTERM:
     1313            bb_info_msg("Received SIGTERM");
     1314            if (opt & OPT_R) /* release on quit */
     1315                perform_release(requested_ip, server_addr);
     1316            goto ret0;
     1317        }
     1318
     1319        /* Is it a packet? */
     1320        if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds))
     1321            continue; /* no */
     1322
     1323        {
     1324            int len;
     1325
     1326            /* A packet is ready, read it */
     1327            if (listen_mode == LISTEN_KERNEL)
     1328                len = udhcp_recv_kernel_packet(&packet, sockfd);
     1329            else
     1330                len = udhcp_recv_raw_packet(&packet, sockfd);
     1331            if (len == -1) {
     1332                /* Error is severe, reopen socket */
     1333                bb_info_msg("Read error: %s, reopening socket", strerror(errno));
     1334                sleep(discover_timeout); /* 3 seconds by default */
     1335                change_listen_mode(listen_mode); /* just close and reopen */
     1336            }
     1337            /* If this packet will turn out to be unrelated/bogus,
     1338             * we will go back and wait for next one.
     1339             * Be sure timeout is properly decreased. */
     1340            already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
     1341            if (len < 0)
     1342                continue;
     1343        }
     1344
     1345        if (packet.xid != xid) {
     1346            log1("xid %x (our is %x), ignoring packet",
     1347                (unsigned)packet.xid, (unsigned)xid);
     1348            continue;
     1349        }
     1350
     1351        /* Ignore packets that aren't for us */
     1352        if (packet.hlen != 6
     1353         || memcmp(packet.chaddr, client_config.client_mac, 6) != 0
     1354        ) {
     1355//FIXME: need to also check that last 10 bytes are zero
     1356            log1("chaddr does not match, ignoring packet"); // log2?
     1357            continue;
     1358        }
     1359
     1360        message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
     1361        if (message == NULL) {
     1362            bb_error_msg("no message type option, ignoring packet");
     1363            continue;
     1364        }
     1365
     1366        switch (state) {
     1367        case INIT_SELECTING:
     1368            /* Must be a DHCPOFFER to one of our xid's */
     1369            if (*message == DHCPOFFER) {
     1370        /* TODO: why we don't just fetch server's IP from IP header? */
     1371                temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
     1372                if (!temp) {
     1373                    bb_error_msg("no server ID, ignoring packet");
     1374                    continue;
     1375                    /* still selecting - this server looks bad */
     1376                }
     1377                /* it IS unaligned sometimes, don't "optimize" */
     1378                move_from_unaligned32(server_addr, temp);
     1379                /*xid = packet.xid; - already is */
     1380                requested_ip = packet.yiaddr;
     1381
     1382                /* enter requesting state */
     1383                state = REQUESTING;
     1384                timeout = 0;
     1385                packet_num = 0;
     1386                already_waited_sec = 0;
     1387            }
     1388            continue;
     1389        case REQUESTING:
     1390        case RENEWING:
     1391        case RENEW_REQUESTED:
     1392        case REBINDING:
     1393            if (*message == DHCPACK) {
     1394                temp = udhcp_get_option(&packet, DHCP_LEASE_TIME);
     1395                if (!temp) {
     1396                    bb_error_msg("no lease time with ACK, using 1 hour lease");
     1397                    lease_seconds = 60 * 60;
    3461398                } else {
    347                     udhcp_run_script(NULL, "leasefail");
    348                     if (client_config.background_if_no_lease) {
    349                         bb_info_msg("No lease, forking to background");
    350                         client_background();
    351                     } else if (client_config.abort_if_no_lease) {
    352                         bb_info_msg("No lease, failing");
    353                         retval = 1;
    354                         goto ret;
    355                     }
    356                     /* wait to try again */
    357                     packet_num = 0;
    358                     timeout = now + 60;
     1399                    /* it IS unaligned sometimes, don't "optimize" */
     1400                    move_from_unaligned32(lease_seconds, temp);
     1401                    lease_seconds = ntohl(lease_seconds);
     1402                    lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */
     1403                    if (lease_seconds < 10) /* and not too small */
     1404                        lease_seconds = 10;
    3591405                }
    360                 break;
    361             case RENEW_REQUESTED:
    362             case REQUESTING:
    363                 if (packet_num < client_config.retries) {
    364                     /* send request packet */
    365                     if (state == RENEW_REQUESTED)
    366                         send_renew(xid, server_addr, requested_ip); /* unicast */
    367                     else send_selecting(xid, server_addr, requested_ip); /* broadcast */
    368 
    369                     timeout = now + ((packet_num == 2) ? 10 : 2);
    370                     packet_num++;
    371                 } else {
    372                     /* timed out, go back to init state */
    373                     if (state == RENEW_REQUESTED)
    374                         udhcp_run_script(NULL, "deconfig");
    375                     state = INIT_SELECTING;
    376                     timeout = now;
    377                     packet_num = 0;
    378                     change_mode(LISTEN_RAW);
    379                 }
    380                 break;
    381             case BOUND:
    382                 /* Lease is starting to run out, time to enter renewing state */
    383                 state = RENEWING;
    384                 change_mode(LISTEN_KERNEL);
    385                 DEBUG("Entering renew state");
    386                 /* fall right through */
    387             case RENEWING:
    388                 /* Either set a new T1, or enter REBINDING state */
    389                 if ((t2 - t1) <= (lease / 14400 + 1)) {
    390                     /* timed out, enter rebinding state */
    391                     state = REBINDING;
    392                     timeout = now + (t2 - t1);
    393                     DEBUG("Entering rebinding state");
    394                 } else {
    395                     /* send a request packet */
    396                     send_renew(xid, server_addr, requested_ip); /* unicast */
    397                     t1 = (t2 - t1) / 2 + t1;
    398                     timeout = start + t1;
    399                 }
    400                 break;
    401             case REBINDING:
    402                 /* Either set a new T2, or enter INIT state */
    403                 if ((lease - t2) <= (lease / 14400 + 1)) {
    404                     /* timed out, enter init state */
    405                     state = INIT_SELECTING;
    406                     bb_info_msg("Lease lost, entering init state");
    407                     udhcp_run_script(NULL, "deconfig");
    408                     timeout = now;
    409                     packet_num = 0;
    410                     change_mode(LISTEN_RAW);
    411                 } else {
    412                     /* send a request packet */
    413                     send_renew(xid, 0, requested_ip); /* broadcast */
    414                     t2 = (lease - t2) / 2 + t2;
    415                     timeout = start + t2;
    416                 }
    417                 break;
    418             case RELEASED:
    419                 /* yah, I know, *you* say it would never happen */
    420                 timeout = INT_MAX;
    421                 break;
    422             }
    423         } else if (listen_mode != LISTEN_NONE && FD_ISSET(sockfd, &rfds)) {
    424             /* a packet is ready, read it */
    425 
    426             if (listen_mode == LISTEN_KERNEL)
    427                 len = udhcp_get_packet(&packet, sockfd);
    428             else len = get_raw_packet(&packet, sockfd);
    429 
    430             if (len == -1 && errno != EINTR) {
    431                 DEBUG("error on read, %s, reopening socket", strerror(errno));
    432                 change_mode(listen_mode); /* just close and reopen */
    433             }
    434             if (len < 0) continue;
    435 
    436             if (packet.xid != xid) {
    437                 DEBUG("Ignoring XID %x (our xid is %x)",
    438                     (unsigned)packet.xid, (unsigned)xid);
    439                 continue;
    440             }
    441 
    442             /* Ignore packets that aren't for us */
    443             if (memcmp(packet.chaddr, client_config.arp, 6)) {
    444                 DEBUG("Packet does not have our chaddr - ignoring");
    445                 continue;
    446             }
    447 
    448             message = get_option(&packet, DHCP_MESSAGE_TYPE);
    449             if (message == NULL) {
    450                 bb_error_msg("cannot get option from packet - ignoring");
    451                 continue;
    452             }
    453 
    454             switch (state) {
    455             case INIT_SELECTING:
    456                 /* Must be a DHCPOFFER to one of our xid's */
    457                 if (*message == DHCPOFFER) {
    458                     temp = get_option(&packet, DHCP_SERVER_ID);
    459                     if (temp) {
    460                         /* can be misaligned, thus memcpy */
    461                         memcpy(&server_addr, temp, 4);
    462                         xid = packet.xid;
    463                         requested_ip = packet.yiaddr;
    464 
    465                         /* enter requesting state */
    466                         state = REQUESTING;
    467                         timeout = now;
     1406#if ENABLE_FEATURE_UDHCPC_ARPING
     1407                if (opt & OPT_a) {
     1408/* RFC 2131 3.1 paragraph 5:
     1409 * "The client receives the DHCPACK message with configuration
     1410 * parameters. The client SHOULD perform a final check on the
     1411 * parameters (e.g., ARP for allocated network address), and notes
     1412 * the duration of the lease specified in the DHCPACK message. At this
     1413 * point, the client is configured. If the client detects that the
     1414 * address is already in use (e.g., through the use of ARP),
     1415 * the client MUST send a DHCPDECLINE message to the server and restarts
     1416 * the configuration process..." */
     1417                    if (!arpping(packet.yiaddr,
     1418                            NULL,
     1419                            (uint32_t) 0,
     1420                            client_config.client_mac,
     1421                            client_config.interface)
     1422                    ) {
     1423                        bb_info_msg("Offered address is in use "
     1424                            "(got ARP reply), declining");
     1425                        send_decline(xid, server_addr, packet.yiaddr);
     1426
     1427                        if (state != REQUESTING)
     1428                            udhcp_run_script(NULL, "deconfig");
     1429                        change_listen_mode(LISTEN_RAW);
     1430                        state = INIT_SELECTING;
     1431                        requested_ip = 0;
     1432                        timeout = tryagain_timeout;
    4681433                        packet_num = 0;
    469                     } else {
    470                         bb_error_msg("no server ID in message");
     1434                        already_waited_sec = 0;
     1435                        continue; /* back to main loop */
    4711436                    }
    4721437                }
    473                 break;
    474             case RENEW_REQUESTED:
    475             case REQUESTING:
    476             case RENEWING:
    477             case REBINDING:
    478                 if (*message == DHCPACK) {
    479                     temp = get_option(&packet, DHCP_LEASE_TIME);
    480                     if (!temp) {
    481                         bb_error_msg("no lease time with ACK, using 1 hour lease");
    482                         lease = 60 * 60;
    483                     } else {
    484                         /* can be misaligned, thus memcpy */
    485                         memcpy(&lease, temp, 4);
    486                         lease = ntohl(lease);
    487                     }
    488 
    489                     /* enter bound state */
    490                     t1 = lease / 2;
    491 
    492                     /* little fixed point for n * .875 */
    493                     t2 = (lease * 7) >> 3;
     1438#endif
     1439                /* enter bound state */
     1440                timeout = lease_seconds / 2;
     1441                {
     1442                    struct in_addr temp_addr;
    4941443                    temp_addr.s_addr = packet.yiaddr;
    4951444                    bb_info_msg("Lease of %s obtained, lease time %u",
    496                         inet_ntoa(temp_addr), (unsigned)lease);
    497                     start = now;
    498                     timeout = start + t1;
    499                     requested_ip = packet.yiaddr;
    500                     udhcp_run_script(&packet,
    501                            ((state == RENEWING || state == REBINDING) ? "renew" : "bound"));
    502 
    503                     state = BOUND;
    504                     change_mode(LISTEN_NONE);
    505                     if (client_config.quit_after_lease) {
    506                         if (client_config.release_on_quit)
    507                             perform_release();
    508                         goto ret0;
    509                     }
    510                     if (!client_config.foreground)
    511                         client_background();
    512 
    513                 } else if (*message == DHCPNAK) {
    514                     /* return to init state */
    515                     bb_info_msg("Received DHCP NAK");
    516                     udhcp_run_script(&packet, "nak");
    517                     if (state != REQUESTING)
    518                         udhcp_run_script(NULL, "deconfig");
    519                     state = INIT_SELECTING;
    520                     timeout = now;
    521                     requested_ip = 0;
    522                     packet_num = 0;
    523                     change_mode(LISTEN_RAW);
    524                     sleep(3); /* avoid excessive network traffic */
     1445                        inet_ntoa(temp_addr), (unsigned)lease_seconds);
    5251446                }
    526                 break;
    527             /* case BOUND, RELEASED: - ignore all packets */
     1447                requested_ip = packet.yiaddr;
     1448                udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew");
     1449
     1450                state = BOUND;
     1451                change_listen_mode(LISTEN_NONE);
     1452                if (opt & OPT_q) { /* quit after lease */
     1453                    if (opt & OPT_R) /* release on quit */
     1454                        perform_release(requested_ip, server_addr);
     1455                    goto ret0;
     1456                }
     1457                /* future renew failures should not exit (JM) */
     1458                opt &= ~OPT_n;
     1459#if BB_MMU /* NOMMU case backgrounded earlier */
     1460                if (!(opt & OPT_f)) {
     1461                    client_background();
     1462                    /* do not background again! */
     1463                    opt = ((opt & ~OPT_b) | OPT_f);
     1464                }
     1465#endif
     1466                already_waited_sec = 0;
     1467                continue; /* back to main loop */
    5281468            }
    529         } else {
    530             int signo = udhcp_sp_read(&rfds);
    531             switch (signo) {
    532             case SIGUSR1:
    533                 perform_renew();
    534                 break;
    535             case SIGUSR2:
    536                 perform_release();
    537                 break;
    538             case SIGTERM:
    539                 bb_info_msg("Received SIGTERM");
    540                 if (client_config.release_on_quit)
    541                     perform_release();
    542                 goto ret0;
     1469            if (*message == DHCPNAK) {
     1470                /* return to init state */
     1471                bb_info_msg("Received DHCP NAK");
     1472                udhcp_run_script(&packet, "nak");
     1473                if (state != REQUESTING)
     1474                    udhcp_run_script(NULL, "deconfig");
     1475                change_listen_mode(LISTEN_RAW);
     1476                sleep(3); /* avoid excessive network traffic */
     1477                state = INIT_SELECTING;
     1478                requested_ip = 0;
     1479                timeout = 0;
     1480                packet_num = 0;
     1481                already_waited_sec = 0;
    5431482            }
     1483            continue;
     1484        /* case BOUND: - ignore all packets */
     1485        /* case RELEASED: - ignore all packets */
    5441486        }
    545     } /* for (;;) */
     1487        /* back to main loop */
     1488    } /* for (;;) - main loop ends */
     1489
    5461490 ret0:
    5471491    retval = 0;
    5481492 ret:
    549     /*if (client_config.pidfile) - remove_pidfile has it's own check */
     1493    /*if (client_config.pidfile) - remove_pidfile has its own check */
    5501494        remove_pidfile(client_config.pidfile);
    5511495    return retval;
Note: See TracChangeset for help on using the changeset viewer.