source: MondoRescue/tags/3.2.2/mindi-busybox/networking/udhcp/dhcpc.c @ 3715

Last change on this file since 3715 was 3715, checked in by Bruno Cornec, 19 months ago

fix dhcpd.c compilation for SLES15 where linux/packet.h is the include needed

File size: 55.7 KB
Line 
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 && __GLIBC_MINOR__ < 2) || 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#if ENABLE_LONG_OPTS
42static const char udhcpc_longopts[] ALIGN1 =
43    "clientid-none\0"  No_argument       "C"
44    "vendorclass\0"    Required_argument "V"
45    "hostname\0"       Required_argument "H"
46    "fqdn\0"           Required_argument "F"
47    "interface\0"      Required_argument "i"
48    "now\0"            No_argument       "n"
49    "pidfile\0"        Required_argument "p"
50    "quit\0"           No_argument       "q"
51    "release\0"        No_argument       "R"
52    "request\0"        Required_argument "r"
53    "script\0"         Required_argument "s"
54    "timeout\0"        Required_argument "T"
55    "retries\0"        Required_argument "t"
56    "tryagain\0"       Required_argument "A"
57    "syslog\0"         No_argument       "S"
58    "request-option\0" Required_argument "O"
59    "no-default-options\0" No_argument   "o"
60    "foreground\0"     No_argument       "f"
61    "background\0"     No_argument       "b"
62    "broadcast\0"      No_argument       "B"
63    IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument       "a")
64    IF_FEATURE_UDHCP_PORT("client-port\0"   Required_argument "P")
65    ;
66#endif
67/* Must match getopt32 option string order */
68enum {
69    OPT_C = 1 << 0,
70    OPT_V = 1 << 1,
71    OPT_H = 1 << 2,
72    OPT_h = 1 << 3,
73    OPT_F = 1 << 4,
74    OPT_i = 1 << 5,
75    OPT_n = 1 << 6,
76    OPT_p = 1 << 7,
77    OPT_q = 1 << 8,
78    OPT_R = 1 << 9,
79    OPT_r = 1 << 10,
80    OPT_s = 1 << 11,
81    OPT_T = 1 << 12,
82    OPT_t = 1 << 13,
83    OPT_S = 1 << 14,
84    OPT_A = 1 << 15,
85    OPT_O = 1 << 16,
86    OPT_o = 1 << 17,
87    OPT_x = 1 << 18,
88    OPT_f = 1 << 19,
89    OPT_B = 1 << 20,
90/* The rest has variable bit positions, need to be clever */
91    OPTBIT_B = 20,
92    USE_FOR_MMU(             OPTBIT_b,)
93    IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
94    IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
95    USE_FOR_MMU(             OPT_b = 1 << OPTBIT_b,)
96    IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
97    IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
98};
99
100
101/*** Script execution code ***/
102
103/* get a rough idea of how long an option will be (rounding up...) */
104static const uint8_t len_of_option_as_string[] = {
105    [OPTION_IP              ] = sizeof("255.255.255.255 "),
106    [OPTION_IP_PAIR         ] = sizeof("255.255.255.255 ") * 2,
107    [OPTION_STATIC_ROUTES   ] = sizeof("255.255.255.255/32 255.255.255.255 "),
108    [OPTION_6RD             ] = sizeof("32 128 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 255.255.255.255 "),
109    [OPTION_STRING          ] = 1,
110    [OPTION_STRING_HOST     ] = 1,
111#if ENABLE_FEATURE_UDHCP_RFC3397
112    [OPTION_DNS_STRING      ] = 1, /* unused */
113    /* Hmmm, this severely overestimates size if SIP_SERVERS option
114     * is in domain name form: N-byte option in binary form
115     * mallocs ~16*N bytes. But it is freed almost at once.
116     */
117    [OPTION_SIP_SERVERS     ] = sizeof("255.255.255.255 "),
118#endif
119//  [OPTION_BOOLEAN         ] = sizeof("yes "),
120    [OPTION_U8              ] = sizeof("255 "),
121    [OPTION_U16             ] = sizeof("65535 "),
122//  [OPTION_S16             ] = sizeof("-32768 "),
123    [OPTION_U32             ] = sizeof("4294967295 "),
124    [OPTION_S32             ] = sizeof("-2147483684 "),
125};
126
127/* note: ip is a pointer to an IP in network order, possibly misaliged */
128static int sprint_nip(char *dest, const char *pre, const uint8_t *ip)
129{
130    return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]);
131}
132
133/* really simple implementation, just count the bits */
134static int mton(uint32_t mask)
135{
136    int i = 0;
137    mask = ntohl(mask); /* 111110000-like bit pattern */
138    while (mask) {
139        i++;
140        mask <<= 1;
141    }
142    return i;
143}
144
145/* Check if a given label represents a valid DNS label
146 * Return pointer to the first character after the label upon success,
147 * NULL otherwise.
148 * See RFC1035, 2.3.1
149 */
150/* We don't need to be particularly anal. For example, allowing _, hyphen
151 * at the end, or leading and trailing dots would be ok, since it
152 * can't be used for attacks. (Leading hyphen can be, if someone uses
153 * cmd "$hostname"
154 * in the script: then hostname may be treated as an option)
155 */
156static const char *valid_domain_label(const char *label)
157{
158    unsigned char ch;
159    unsigned pos = 0;
160
161    for (;;) {
162        ch = *label;
163        if ((ch|0x20) < 'a' || (ch|0x20) > 'z') {
164            if (pos == 0) {
165                /* label must begin with letter */
166                return NULL;
167            }
168            if (ch < '0' || ch > '9') {
169                if (ch == '\0' || ch == '.')
170                    return label;
171                /* DNS allows only '-', but we are more permissive */
172                if (ch != '-' && ch != '_')
173                    return NULL;
174            }
175        }
176        label++;
177        pos++;
178        //Do we want this?
179        //if (pos > 63) /* NS_MAXLABEL; labels must be 63 chars or less */
180        //  return NULL;
181    }
182}
183
184/* Check if a given name represents a valid DNS name */
185/* See RFC1035, 2.3.1 */
186static int good_hostname(const char *name)
187{
188    //const char *start = name;
189
190    for (;;) {
191        name = valid_domain_label(name);
192        if (!name)
193            return 0;
194        if (!name[0])
195            return 1;
196            //Do we want this?
197            //return ((name - start) < 1025); /* NS_MAXDNAME */
198        name++;
199    }
200}
201
202/* Create "opt_name=opt_value" string */
203static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name)
204{
205    unsigned upper_length;
206    int len, type, optlen;
207    char *dest, *ret;
208
209    /* option points to OPT_DATA, need to go back to get OPT_LEN */
210    len = option[-OPT_DATA + OPT_LEN];
211
212    type = optflag->flags & OPTION_TYPE_MASK;
213    optlen = dhcp_option_lengths[type];
214    upper_length = len_of_option_as_string[type]
215        * ((unsigned)(len + optlen - 1) / (unsigned)optlen);
216
217    dest = ret = xmalloc(upper_length + strlen(opt_name) + 2);
218    dest += sprintf(ret, "%s=", opt_name);
219
220    while (len >= optlen) {
221        switch (type) {
222        case OPTION_IP:
223        case OPTION_IP_PAIR:
224            dest += sprint_nip(dest, "", option);
225            if (type == OPTION_IP)
226                break;
227            dest += sprint_nip(dest, "/", option + 4);
228            break;
229//      case OPTION_BOOLEAN:
230//          dest += sprintf(dest, *option ? "yes" : "no");
231//          break;
232        case OPTION_U8:
233            dest += sprintf(dest, "%u", *option);
234            break;
235//      case OPTION_S16:
236        case OPTION_U16: {
237            uint16_t val_u16;
238            move_from_unaligned16(val_u16, option);
239            dest += sprintf(dest, "%u", ntohs(val_u16));
240            break;
241        }
242        case OPTION_S32:
243        case OPTION_U32: {
244            uint32_t val_u32;
245            move_from_unaligned32(val_u32, option);
246            dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32));
247            break;
248        }
249        /* Note: options which use 'return' instead of 'break'
250         * (for example, OPTION_STRING) skip the code which handles
251         * the case of list of options.
252         */
253        case OPTION_STRING:
254        case OPTION_STRING_HOST:
255            memcpy(dest, option, len);
256            dest[len] = '\0';
257            if (type == OPTION_STRING_HOST && !good_hostname(dest))
258                safe_strncpy(dest, "bad", len);
259            return ret;
260        case OPTION_STATIC_ROUTES: {
261            /* Option binary format:
262             * mask [one byte, 0..32]
263             * ip [big endian, 0..4 bytes depending on mask]
264             * router [big endian, 4 bytes]
265             * may be repeated
266             *
267             * We convert it to a string "IP/MASK ROUTER IP2/MASK2 ROUTER2"
268             */
269            const char *pfx = "";
270
271            while (len >= 1 + 4) { /* mask + 0-byte ip + router */
272                uint32_t nip;
273                uint8_t *p;
274                unsigned mask;
275                int bytes;
276
277                mask = *option++;
278                if (mask > 32)
279                    break;
280                len--;
281
282                nip = 0;
283                p = (void*) &nip;
284                bytes = (mask + 7) / 8; /* 0 -> 0, 1..8 -> 1, 9..16 -> 2 etc */
285                while (--bytes >= 0) {
286                    *p++ = *option++;
287                    len--;
288                }
289                if (len < 4)
290                    break;
291
292                /* print ip/mask */
293                dest += sprint_nip(dest, pfx, (void*) &nip);
294                pfx = " ";
295                dest += sprintf(dest, "/%u ", mask);
296                /* print router */
297                dest += sprint_nip(dest, "", option);
298                option += 4;
299                len -= 4;
300            }
301
302            return ret;
303        }
304        case OPTION_6RD:
305            /* Option binary format (see RFC 5969):
306             *  0                   1                   2                   3
307             *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
308             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
309             * |  OPTION_6RD   | option-length |  IPv4MaskLen  |  6rdPrefixLen |
310             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
311             * |                           6rdPrefix                           |
312             * ...                        (16 octets)                        ...
313             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
314             * ...                   6rdBRIPv4Address(es)                    ...
315             * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
316             * We convert it to a string
317             * "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address..."
318             *
319             * Sanity check: ensure that our length is at least 22 bytes, that
320             * IPv4MaskLen <= 32,
321             * 6rdPrefixLen <= 128,
322             * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128
323             * (2nd condition need no check - it follows from 1st and 3rd).
324             * Else, return envvar with empty value ("optname=")
325             */
326            if (len >= (1 + 1 + 16 + 4)
327             && option[0] <= 32
328             && (option[1] + 32 - option[0]) <= 128
329            ) {
330                /* IPv4MaskLen */
331                dest += sprintf(dest, "%u ", *option++);
332                /* 6rdPrefixLen */
333                dest += sprintf(dest, "%u ", *option++);
334                /* 6rdPrefix */
335                dest += sprint_nip6(dest, /* "", */ option);
336                option += 16;
337                len -= 1 + 1 + 16 + 4;
338                /* "+ 4" above corresponds to the length of IPv4 addr
339                 * we consume in the loop below */
340                while (1) {
341                    /* 6rdBRIPv4Address(es) */
342                    dest += sprint_nip(dest, " ", option);
343                    option += 4;
344                    len -= 4; /* do we have yet another 4+ bytes? */
345                    if (len < 0)
346                        break; /* no */
347                }
348            }
349
350            return ret;
351#if ENABLE_FEATURE_UDHCP_RFC3397
352        case OPTION_DNS_STRING:
353            /* unpack option into dest; use ret for prefix (i.e., "optname=") */
354            dest = dname_dec(option, len, ret);
355            if (dest) {
356                free(ret);
357                return dest;
358            }
359            /* error. return "optname=" string */
360            return ret;
361        case OPTION_SIP_SERVERS:
362            /* Option binary format:
363             * type: byte
364             * type=0: domain names, dns-compressed
365             * type=1: IP addrs
366             */
367            option++;
368            len--;
369            if (option[-1] == 0) {
370                dest = dname_dec(option, len, ret);
371                if (dest) {
372                    free(ret);
373                    return dest;
374                }
375            } else
376            if (option[-1] == 1) {
377                const char *pfx = "";
378                while (1) {
379                    len -= 4;
380                    if (len < 0)
381                        break;
382                    dest += sprint_nip(dest, pfx, option);
383                    pfx = " ";
384                    option += 4;
385                }
386            }
387            return ret;
388#endif
389        } /* switch */
390
391        /* If we are here, try to format any remaining data
392         * in the option as another, similarly-formatted option
393         */
394        option += optlen;
395        len -= optlen;
396// TODO: it can be a list only if (optflag->flags & OPTION_LIST).
397// Should we bail out/warn if we see multi-ip option which is
398// not allowed to be such (for example, DHCP_BROADCAST)? -
399        if (len < optlen /* || !(optflag->flags & OPTION_LIST) */)
400            break;
401        *dest++ = ' ';
402        *dest = '\0';
403    } /* while */
404
405    return ret;
406}
407
408/* put all the parameters into the environment */
409static char **fill_envp(struct dhcp_packet *packet)
410{
411    int envc;
412    int i;
413    char **envp, **curr;
414    const char *opt_name;
415    uint8_t *temp;
416    uint8_t overload = 0;
417
418#define BITMAP unsigned
419#define BBITS (sizeof(BITMAP) * 8)
420#define BMASK(i) (1 << (i & (sizeof(BITMAP) * 8 - 1)))
421#define FOUND_OPTS(i) (found_opts[(unsigned)i / BBITS])
422    BITMAP found_opts[256 / BBITS];
423
424    memset(found_opts, 0, sizeof(found_opts));
425
426    /* We need 6 elements for:
427     * "interface=IFACE"
428     * "ip=N.N.N.N" from packet->yiaddr
429     * "siaddr=IP" from packet->siaddr_nip (unless 0)
430     * "boot_file=FILE" from packet->file (unless overloaded)
431     * "sname=SERVER_HOSTNAME" from packet->sname (unless overloaded)
432     * terminating NULL
433     */
434    envc = 6;
435    /* +1 element for each option, +2 for subnet option: */
436    if (packet) {
437        /* note: do not search for "pad" (0) and "end" (255) options */
438//TODO: change logic to scan packet _once_
439        for (i = 1; i < 255; i++) {
440            temp = udhcp_get_option(packet, i);
441            if (temp) {
442                if (i == DHCP_OPTION_OVERLOAD)
443                    overload = *temp;
444                else if (i == DHCP_SUBNET)
445                    envc++; /* for $mask */
446                envc++;
447                /*if (i != DHCP_MESSAGE_TYPE)*/
448                FOUND_OPTS(i) |= BMASK(i);
449            }
450        }
451    }
452    curr = envp = xzalloc(sizeof(envp[0]) * envc);
453
454    *curr = xasprintf("interface=%s", client_config.interface);
455    putenv(*curr++);
456
457    if (!packet)
458        return envp;
459
460    /* Export BOOTP fields. Fields we don't (yet?) export:
461     * uint8_t op;      // always BOOTREPLY
462     * uint8_t htype;   // hardware address type. 1 = 10mb ethernet
463     * uint8_t hlen;    // hardware address length
464     * uint8_t hops;    // used by relay agents only
465     * uint32_t xid;
466     * uint16_t secs;   // elapsed since client began acquisition/renewal
467     * uint16_t flags;  // only one flag so far: bcast. Never set by server
468     * uint32_t ciaddr; // client IP (usually == yiaddr. can it be different
469     *                  // if during renew server wants to give us differn IP?)
470     * uint32_t gateway_nip; // relay agent IP address
471     * uint8_t chaddr[16]; // link-layer client hardware address (MAC)
472     * TODO: export gateway_nip as $giaddr?
473     */
474    /* Most important one: yiaddr as $ip */
475    *curr = xmalloc(sizeof("ip=255.255.255.255"));
476    sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr);
477    putenv(*curr++);
478    if (packet->siaddr_nip) {
479        /* IP address of next server to use in bootstrap */
480        *curr = xmalloc(sizeof("siaddr=255.255.255.255"));
481        sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip);
482        putenv(*curr++);
483    }
484    if (!(overload & FILE_FIELD) && packet->file[0]) {
485        /* watch out for invalid packets */
486        *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file);
487        putenv(*curr++);
488    }
489    if (!(overload & SNAME_FIELD) && packet->sname[0]) {
490        /* watch out for invalid packets */
491        *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname);
492        putenv(*curr++);
493    }
494
495    /* Export known DHCP options */
496    opt_name = dhcp_option_strings;
497    i = 0;
498    while (*opt_name) {
499        uint8_t code = dhcp_optflags[i].code;
500        BITMAP *found_ptr = &FOUND_OPTS(code);
501        BITMAP found_mask = BMASK(code);
502        if (!(*found_ptr & found_mask))
503            goto next;
504        *found_ptr &= ~found_mask; /* leave only unknown options */
505        temp = udhcp_get_option(packet, code);
506        *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name);
507        putenv(*curr++);
508        if (code == DHCP_SUBNET) {
509            /* Subnet option: make things like "$ip/$mask" possible */
510            uint32_t subnet;
511            move_from_unaligned32(subnet, temp);
512            *curr = xasprintf("mask=%u", mton(subnet));
513            putenv(*curr++);
514        }
515 next:
516        opt_name += strlen(opt_name) + 1;
517        i++;
518    }
519    /* Export unknown options */
520    for (i = 0; i < 256;) {
521        BITMAP bitmap = FOUND_OPTS(i);
522        if (!bitmap) {
523            i += BBITS;
524            continue;
525        }
526        if (bitmap & BMASK(i)) {
527            unsigned len, ofs;
528
529            temp = udhcp_get_option(packet, i);
530            /* udhcp_get_option returns ptr to data portion,
531             * need to go back to get len
532             */
533            len = temp[-OPT_DATA + OPT_LEN];
534            *curr = xmalloc(sizeof("optNNN=") + 1 + len*2);
535            ofs = sprintf(*curr, "opt%u=", i);
536            *bin2hex(*curr + ofs, (void*) temp, len) = '\0';
537            putenv(*curr++);
538        }
539        i++;
540    }
541
542    return envp;
543}
544
545/* Call a script with a par file and env vars */
546static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
547{
548    char **envp, **curr;
549    char *argv[3];
550
551    envp = fill_envp(packet);
552
553    /* call script */
554    log1("Executing %s %s", client_config.script, name);
555    argv[0] = (char*) client_config.script;
556    argv[1] = (char*) name;
557    argv[2] = NULL;
558    spawn_and_wait(argv);
559
560    for (curr = envp; *curr; curr++) {
561        log2(" %s", *curr);
562        bb_unsetenv_and_free(*curr);
563    }
564    free(envp);
565}
566
567
568/*** Sending/receiving packets ***/
569
570static ALWAYS_INLINE uint32_t random_xid(void)
571{
572    return rand();
573}
574
575/* Initialize the packet with the proper defaults */
576static void init_packet(struct dhcp_packet *packet, char type)
577{
578    uint16_t secs;
579
580    /* Fill in: op, htype, hlen, cookie fields; message type option: */
581    udhcp_init_header(packet, type);
582
583    packet->xid = random_xid();
584
585    client_config.last_secs = monotonic_sec();
586    if (client_config.first_secs == 0)
587        client_config.first_secs = client_config.last_secs;
588    secs = client_config.last_secs - client_config.first_secs;
589    packet->secs = htons(secs);
590
591    memcpy(packet->chaddr, client_config.client_mac, 6);
592    if (client_config.clientid)
593        udhcp_add_binary_option(packet, client_config.clientid);
594}
595
596static void add_client_options(struct dhcp_packet *packet)
597{
598    int i, end, len;
599
600    udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE));
601
602    /* Add a "param req" option with the list of options we'd like to have
603     * from stubborn DHCP servers. Pull the data from the struct in common.c.
604     * No bounds checking because it goes towards the head of the packet. */
605    end = udhcp_end_option(packet->options);
606    len = 0;
607    for (i = 1; i < DHCP_END; i++) {
608        if (client_config.opt_mask[i >> 3] & (1 << (i & 7))) {
609            packet->options[end + OPT_DATA + len] = i;
610            len++;
611        }
612    }
613    if (len) {
614        packet->options[end + OPT_CODE] = DHCP_PARAM_REQ;
615        packet->options[end + OPT_LEN] = len;
616        packet->options[end + OPT_DATA + len] = DHCP_END;
617    }
618
619    if (client_config.vendorclass)
620        udhcp_add_binary_option(packet, client_config.vendorclass);
621    if (client_config.hostname)
622        udhcp_add_binary_option(packet, client_config.hostname);
623    if (client_config.fqdn)
624        udhcp_add_binary_option(packet, client_config.fqdn);
625
626    /* Request broadcast replies if we have no IP addr */
627    if ((option_mask32 & OPT_B) && packet->ciaddr == 0)
628        packet->flags |= htons(BROADCAST_FLAG);
629
630    /* Add -x options if any */
631    {
632        struct option_set *curr = client_config.options;
633        while (curr) {
634            udhcp_add_binary_option(packet, curr->data);
635            curr = curr->next;
636        }
637//      if (client_config.sname)
638//          strncpy((char*)packet->sname, client_config.sname, sizeof(packet->sname) - 1);
639//      if (client_config.boot_file)
640//          strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1);
641    }
642
643    // This will be needed if we remove -V VENDOR_STR in favor of
644    // -x vendor:VENDOR_STR
645    //if (!udhcp_find_option(packet.options, DHCP_VENDOR))
646    //  /* not set, set the default vendor ID */
647    //  ...add (DHCP_VENDOR, "udhcp "BB_VER) opt...
648}
649
650/* RFC 2131
651 * 4.4.4 Use of broadcast and unicast
652 *
653 * The DHCP client broadcasts DHCPDISCOVER, DHCPREQUEST and DHCPINFORM
654 * messages, unless the client knows the address of a DHCP server.
655 * The client unicasts DHCPRELEASE messages to the server. Because
656 * the client is declining the use of the IP address supplied by the server,
657 * the client broadcasts DHCPDECLINE messages.
658 *
659 * When the DHCP client knows the address of a DHCP server, in either
660 * INIT or REBOOTING state, the client may use that address
661 * in the DHCPDISCOVER or DHCPREQUEST rather than the IP broadcast address.
662 * The client may also use unicast to send DHCPINFORM messages
663 * to a known DHCP server. If the client receives no response to DHCP
664 * messages sent to the IP address of a known DHCP server, the DHCP
665 * client reverts to using the IP broadcast address.
666 */
667
668static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet)
669{
670    return udhcp_send_raw_packet(packet,
671        /*src*/ INADDR_ANY, CLIENT_PORT,
672        /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
673        client_config.ifindex);
674}
675
676/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
677/* NOINLINE: limit stack usage in caller */
678static NOINLINE int send_discover(uint32_t xid, uint32_t requested)
679{
680    struct dhcp_packet packet;
681
682    /* Fill in: op, htype, hlen, cookie, chaddr fields,
683     * random xid field (we override it below),
684     * client-id option (unless -C), message type option:
685     */
686    init_packet(&packet, DHCPDISCOVER);
687
688    packet.xid = xid;
689    if (requested)
690        udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
691
692    /* Add options: maxsize,
693     * optionally: hostname, fqdn, vendorclass,
694     * "param req" option according to -O, options specified with -x
695     */
696    add_client_options(&packet);
697
698    bb_info_msg("Sending discover...");
699    return raw_bcast_from_client_config_ifindex(&packet);
700}
701
702/* Broadcast a DHCP request message */
703/* RFC 2131 3.1 paragraph 3:
704 * "The client _broadcasts_ a DHCPREQUEST message..."
705 */
706/* NOINLINE: limit stack usage in caller */
707static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested)
708{
709    struct dhcp_packet packet;
710    struct in_addr addr;
711
712/*
713 * RFC 2131 4.3.2 DHCPREQUEST message
714 * ...
715 * If the DHCPREQUEST message contains a 'server identifier'
716 * option, the message is in response to a DHCPOFFER message.
717 * Otherwise, the message is a request to verify or extend an
718 * existing lease. If the client uses a 'client identifier'
719 * in a DHCPREQUEST message, it MUST use that same 'client identifier'
720 * in all subsequent messages. If the client included a list
721 * of requested parameters in a DHCPDISCOVER message, it MUST
722 * include that list in all subsequent messages.
723 */
724    /* Fill in: op, htype, hlen, cookie, chaddr fields,
725     * random xid field (we override it below),
726     * client-id option (unless -C), message type option:
727     */
728    init_packet(&packet, DHCPREQUEST);
729
730    packet.xid = xid;
731    udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
732
733    udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
734
735    /* Add options: maxsize,
736     * optionally: hostname, fqdn, vendorclass,
737     * "param req" option according to -O, and options specified with -x
738     */
739    add_client_options(&packet);
740
741    addr.s_addr = requested;
742    bb_info_msg("Sending select for %s...", inet_ntoa(addr));
743    return raw_bcast_from_client_config_ifindex(&packet);
744}
745
746/* Unicast or broadcast a DHCP renew message */
747/* NOINLINE: limit stack usage in caller */
748static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
749{
750    struct dhcp_packet packet;
751
752/*
753 * RFC 2131 4.3.2 DHCPREQUEST message
754 * ...
755 * DHCPREQUEST generated during RENEWING state:
756 *
757 * 'server identifier' MUST NOT be filled in, 'requested IP address'
758 * option MUST NOT be filled in, 'ciaddr' MUST be filled in with
759 * client's IP address. In this situation, the client is completely
760 * configured, and is trying to extend its lease. This message will
761 * be unicast, so no relay agents will be involved in its
762 * transmission.  Because 'giaddr' is therefore not filled in, the
763 * DHCP server will trust the value in 'ciaddr', and use it when
764 * replying to the client.
765 */
766    /* Fill in: op, htype, hlen, cookie, chaddr fields,
767     * random xid field (we override it below),
768     * client-id option (unless -C), message type option:
769     */
770    init_packet(&packet, DHCPREQUEST);
771
772    packet.xid = xid;
773    packet.ciaddr = ciaddr;
774
775    /* Add options: maxsize,
776     * optionally: hostname, fqdn, vendorclass,
777     * "param req" option according to -O, and options specified with -x
778     */
779    add_client_options(&packet);
780
781    bb_info_msg("Sending renew...");
782    if (server)
783        return udhcp_send_kernel_packet(&packet,
784            ciaddr, CLIENT_PORT,
785            server, SERVER_PORT);
786    return raw_bcast_from_client_config_ifindex(&packet);
787}
788
789#if ENABLE_FEATURE_UDHCPC_ARPING
790/* Broadcast a DHCP decline message */
791/* NOINLINE: limit stack usage in caller */
792static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t requested)
793{
794    struct dhcp_packet packet;
795
796    /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
797     * client-id option (unless -C), message type option:
798     */
799    init_packet(&packet, DHCPDECLINE);
800
801#if 0
802    /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client,
803     * but in case the server is buggy and wants DHCPDECLINE's xid
804     * to match the xid which started entire handshake,
805     * we use the same xid we used in initial DHCPDISCOVER:
806     */
807    packet.xid = xid;
808#endif
809    /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */
810    udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested);
811
812    udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
813
814    bb_info_msg("Sending decline...");
815    return raw_bcast_from_client_config_ifindex(&packet);
816}
817#endif
818
819/* Unicast a DHCP release message */
820static int send_release(uint32_t server, uint32_t ciaddr)
821{
822    struct dhcp_packet packet;
823
824    /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields,
825     * client-id option (unless -C), message type option:
826     */
827    init_packet(&packet, DHCPRELEASE);
828
829    /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */
830    packet.ciaddr = ciaddr;
831
832    udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
833
834    bb_info_msg("Sending release...");
835    return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT);
836}
837
838/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */
839/* NOINLINE: limit stack usage in caller */
840static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
841{
842    int bytes;
843    struct ip_udp_dhcp_packet packet;
844    uint16_t check;
845#ifdef PACKET_AUXDATA
846    unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))];
847    struct cmsghdr *cmsg;
848#endif
849    struct iovec iov;
850    struct msghdr msg;
851
852#ifdef PACKET_AUXDATA
853    /* used to use just safe_read(fd, &packet, sizeof(packet))
854     * but we need to check for TP_STATUS_CSUMNOTREADY :(
855     */
856    iov.iov_base = &packet;
857    iov.iov_len = sizeof(packet);
858    memset(&msg, 0, sizeof(msg));
859    msg.msg_iov = &iov;
860    msg.msg_iovlen = 1;
861    msg.msg_control = cmsgbuf;
862    msg.msg_controllen = sizeof(cmsgbuf);
863    for (;;) {
864        bytes = recvmsg(fd, &msg, 0);
865        if (bytes < 0) {
866            if (errno == EINTR)
867                continue;
868            log1("Packet read error, ignoring");
869            /* NB: possible down interface, etc. Caller should pause. */
870            return bytes; /* returns -1 */
871        }
872        break;
873    }
874#else
875    memset(&packet, 0, sizeof(packet));
876    bytes = safe_read(fd, &packet, sizeof(packet));
877    if (bytes < 0) {
878        log1("Packet read error, ignoring");
879        /* NB: possible down interface, etc. Caller should pause. */
880        return bytes; /* returns -1 */
881    }
882#endif
883
884    if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) {
885        log1("Packet is too short, ignoring");
886        return -2;
887    }
888
889    if (bytes < ntohs(packet.ip.tot_len)) {
890        /* packet is bigger than sizeof(packet), we did partial read */
891        log1("Oversized packet, ignoring");
892        return -2;
893    }
894
895    /* ignore any extra garbage bytes */
896    bytes = ntohs(packet.ip.tot_len);
897
898    /* make sure its the right packet for us, and that it passes sanity checks */
899    if (packet.ip.protocol != IPPROTO_UDP
900     || packet.ip.version != IPVERSION
901     || packet.ip.ihl != (sizeof(packet.ip) >> 2)
902     || packet.udp.dest != htons(CLIENT_PORT)
903    /* || bytes > (int) sizeof(packet) - can't happen */
904     || ntohs(packet.udp.len) != (uint16_t)(bytes - sizeof(packet.ip))
905    ) {
906        log1("Unrelated/bogus packet, ignoring");
907        return -2;
908    }
909
910    /* verify IP checksum */
911    check = packet.ip.check;
912    packet.ip.check = 0;
913    if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) {
914        log1("Bad IP header checksum, ignoring");
915        return -2;
916    }
917
918#ifdef PACKET_AUXDATA
919    for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
920        if (cmsg->cmsg_level == SOL_PACKET
921         && cmsg->cmsg_type == PACKET_AUXDATA
922        ) {
923            /* some VMs don't checksum UDP and TCP data
924             * they send to the same physical machine,
925             * here we detect this case:
926             */
927            struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg);
928            if (aux->tp_status & TP_STATUS_CSUMNOTREADY)
929                goto skip_udp_sum_check;
930        }
931    }
932#endif
933
934    /* verify UDP checksum. IP header has to be modified for this */
935    memset(&packet.ip, 0, offsetof(struct iphdr, protocol));
936    /* ip.xx fields which are not memset: protocol, check, saddr, daddr */
937    packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
938    check = packet.udp.check;
939    packet.udp.check = 0;
940    if (check && check != inet_cksum((uint16_t *)&packet, bytes)) {
941        log1("Packet with bad UDP checksum received, ignoring");
942        return -2;
943    }
944#ifdef PACKET_AUXDATA
945 skip_udp_sum_check:
946#endif
947
948    if (packet.data.cookie != htonl(DHCP_MAGIC)) {
949        bb_info_msg("Packet with bad magic, ignoring");
950        return -2;
951    }
952
953    log1("Received a packet");
954    udhcp_dump_packet(&packet.data);
955
956    bytes -= sizeof(packet.ip) + sizeof(packet.udp);
957    memcpy(dhcp_pkt, &packet.data, bytes);
958    return bytes;
959}
960
961
962/*** Main ***/
963
964static int sockfd = -1;
965
966#define LISTEN_NONE   0
967#define LISTEN_KERNEL 1
968#define LISTEN_RAW    2
969static smallint listen_mode;
970
971/* initial state: (re)start DHCP negotiation */
972#define INIT_SELECTING  0
973/* discover was sent, DHCPOFFER reply received */
974#define REQUESTING      1
975/* select/renew was sent, DHCPACK reply received */
976#define BOUND           2
977/* half of lease passed, want to renew it by sending unicast renew requests */
978#define RENEWING        3
979/* renew requests were not answered, lease is almost over, send broadcast renew */
980#define REBINDING       4
981/* manually requested renew (SIGUSR1) */
982#define RENEW_REQUESTED 5
983/* release, possibly manually requested (SIGUSR2) */
984#define RELEASED        6
985static smallint state;
986
987static int udhcp_raw_socket(int ifindex)
988{
989    int fd;
990    struct sockaddr_ll sock;
991
992    /*
993     * Comment:
994     *
995     *  I've selected not to see LL header, so BPF doesn't see it, too.
996     *  The filter may also pass non-IP and non-ARP packets, but we do
997     *  a more complete check when receiving the message in userspace.
998     *
999     * and filter shamelessly stolen from:
1000     *
1001     *  http://www.flamewarmaster.de/software/dhcpclient/
1002     *
1003     * There are a few other interesting ideas on that page (look under
1004     * "Motivation").  Use of netlink events is most interesting.  Think
1005     * of various network servers listening for events and reconfiguring.
1006     * That would obsolete sending HUP signals and/or make use of restarts.
1007     *
1008     * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
1009     * License: GPL v2.
1010     *
1011     * TODO: make conditional?
1012     */
1013    static const struct sock_filter filter_instr[] = {
1014        /* load 9th byte (protocol) */
1015        BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
1016        /* jump to L1 if it is IPPROTO_UDP, else to L4 */
1017        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
1018        /* L1: load halfword from offset 6 (flags and frag offset) */
1019        BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
1020        /* jump to L4 if any bits in frag offset field are set, else to L2 */
1021        BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
1022        /* L2: skip IP header (load index reg with header len) */
1023        BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
1024        /* load udp destination port from halfword[header_len + 2] */
1025        BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
1026        /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */
1027        BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
1028        /* L3: accept packet */
1029        BPF_STMT(BPF_RET|BPF_K, 0xffffffff),
1030        /* L4: discard packet */
1031        BPF_STMT(BPF_RET|BPF_K, 0),
1032    };
1033    static const struct sock_fprog filter_prog = {
1034        .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
1035        /* casting const away: */
1036        .filter = (struct sock_filter *) filter_instr,
1037    };
1038
1039    log1("Opening raw socket on ifindex %d", ifindex); //log2?
1040
1041    fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
1042    log1("Got raw socket fd"); //log2?
1043
1044    sock.sll_family = AF_PACKET;
1045    sock.sll_protocol = htons(ETH_P_IP);
1046    sock.sll_ifindex = ifindex;
1047    xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
1048
1049    if (CLIENT_PORT == 68) {
1050        /* Use only if standard port is in use */
1051        /* Ignoring error (kernel may lack support for this) */
1052        if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
1053                sizeof(filter_prog)) >= 0)
1054            log1("Attached filter to raw socket fd"); // log?
1055    }
1056
1057#ifdef PACKET_AUXDATA
1058    if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA,
1059            &const_int_1, sizeof(int)) < 0
1060    ) {
1061        if (errno != ENOPROTOOPT)
1062            log1("Can't set PACKET_AUXDATA on raw socket");
1063    }
1064#else
1065    sock.sll_family = AF_PACKET;
1066    sock.sll_protocol = htons(ETH_P_IP);
1067    sock.sll_ifindex = ifindex;
1068    xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
1069#endif
1070
1071    log1("Created raw socket");
1072
1073    return fd;
1074}
1075
1076static void change_listen_mode(int new_mode)
1077{
1078    log1("Entering listen mode: %s",
1079        new_mode != LISTEN_NONE
1080            ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw")
1081            : "none"
1082    );
1083
1084    listen_mode = new_mode;
1085    if (sockfd >= 0) {
1086        close(sockfd);
1087        sockfd = -1;
1088    }
1089    if (new_mode == LISTEN_KERNEL)
1090        sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface);
1091    else if (new_mode != LISTEN_NONE)
1092        sockfd = udhcp_raw_socket(client_config.ifindex);
1093    /* else LISTEN_NONE: sockfd stays closed */
1094}
1095
1096/* Called only on SIGUSR1 */
1097static void perform_renew(void)
1098{
1099    bb_info_msg("Performing a DHCP renew");
1100    switch (state) {
1101    case BOUND:
1102        change_listen_mode(LISTEN_KERNEL);
1103    case RENEWING:
1104    case REBINDING:
1105        state = RENEW_REQUESTED;
1106        break;
1107    case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
1108        udhcp_run_script(NULL, "deconfig");
1109    case REQUESTING:
1110    case RELEASED:
1111        change_listen_mode(LISTEN_RAW);
1112        state = INIT_SELECTING;
1113        break;
1114    case INIT_SELECTING:
1115        break;
1116    }
1117}
1118
1119static void perform_release(uint32_t server_addr, uint32_t requested_ip)
1120{
1121    char buffer[sizeof("255.255.255.255")];
1122    struct in_addr temp_addr;
1123
1124    /* send release packet */
1125    if (state == BOUND || state == RENEWING || state == REBINDING) {
1126        temp_addr.s_addr = server_addr;
1127        strcpy(buffer, inet_ntoa(temp_addr));
1128        temp_addr.s_addr = requested_ip;
1129        bb_info_msg("Unicasting a release of %s to %s",
1130                inet_ntoa(temp_addr), buffer);
1131        send_release(server_addr, requested_ip); /* unicast */
1132        udhcp_run_script(NULL, "deconfig");
1133    }
1134    bb_info_msg("Entering released state");
1135
1136    change_listen_mode(LISTEN_NONE);
1137    state = RELEASED;
1138}
1139
1140static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
1141{
1142    uint8_t *storage;
1143    int len = strnlen(str, 255);
1144    storage = xzalloc(len + extra + OPT_DATA);
1145    storage[OPT_CODE] = code;
1146    storage[OPT_LEN] = len + extra;
1147    memcpy(storage + extra + OPT_DATA, str, len);
1148    return storage;
1149}
1150
1151#if BB_MMU
1152static void client_background(void)
1153{
1154    bb_daemonize(0);
1155    logmode &= ~LOGMODE_STDIO;
1156    /* rewrite pidfile, as our pid is different now */
1157    write_pidfile(client_config.pidfile);
1158}
1159#endif
1160
1161//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
1162//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
1163//usage:#else
1164//usage:# define IF_UDHCP_VERBOSE(...)
1165//usage:#endif
1166//usage:#define udhcpc_trivial_usage
1167//usage:       "[-fbnq"IF_UDHCP_VERBOSE("v")"oCRB] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n"
1168//usage:       "    [-V VENDOR] [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
1169//usage:#define udhcpc_full_usage "\n"
1170//usage:    IF_LONG_OPTS(
1171//usage:     "\n    -i,--interface IFACE    Interface to use (default eth0)"
1172//usage:     "\n    -p,--pidfile FILE   Create pidfile"
1173//usage:     "\n    -s,--script PROG    Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1174//usage:     "\n    -B,--broadcast      Request broadcast replies"
1175//usage:     "\n    -t,--retries N      Send up to N discover packets"
1176//usage:     "\n    -T,--timeout N      Pause between packets (default 3 seconds)"
1177//usage:     "\n    -A,--tryagain N     Wait N seconds after failure (default 20)"
1178//usage:     "\n    -f,--foreground     Run in foreground"
1179//usage:    USE_FOR_MMU(
1180//usage:     "\n    -b,--background     Background if lease is not obtained"
1181//usage:    )
1182//usage:     "\n    -n,--now        Exit if lease is not obtained"
1183//usage:     "\n    -q,--quit       Exit after obtaining lease"
1184//usage:     "\n    -R,--release        Release IP on exit"
1185//usage:     "\n    -S,--syslog     Log to syslog too"
1186//usage:    IF_FEATURE_UDHCP_PORT(
1187//usage:     "\n    -P,--client-port N  Use port N (default 68)"
1188//usage:    )
1189//usage:    IF_FEATURE_UDHCPC_ARPING(
1190//usage:     "\n    -a,--arping     Use arping to validate offered address"
1191//usage:    )
1192//usage:     "\n    -O,--request-option OPT Request option OPT from server (cumulative)"
1193//usage:     "\n    -o,--no-default-options Don't request any options (unless -O is given)"
1194//usage:     "\n    -r,--request IP     Request this IP address"
1195//usage:     "\n    -x OPT:VAL      Include option OPT in sent packets (cumulative)"
1196//usage:     "\n                Examples of string, numeric, and hex byte opts:"
1197//usage:     "\n                -x hostname:bbox - option 12"
1198//usage:     "\n                -x lease:3600 - option 51 (lease time)"
1199//usage:     "\n                -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
1200//usage:     "\n    -F,--fqdn NAME      Ask server to update DNS mapping for NAME"
1201//usage:     "\n    -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')"
1202//usage:     "\n    -C,--clientid-none  Don't send MAC as client identifier"
1203//usage:    IF_UDHCP_VERBOSE(
1204//usage:     "\n    -v          Verbose"
1205//usage:    )
1206//usage:    )
1207//usage:    IF_NOT_LONG_OPTS(
1208//usage:     "\n    -i IFACE    Interface to use (default eth0)"
1209//usage:     "\n    -p FILE     Create pidfile"
1210//usage:     "\n    -s PROG     Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")"
1211//usage:     "\n    -B      Request broadcast replies"
1212//usage:     "\n    -t N        Send up to N discover packets"
1213//usage:     "\n    -T N        Pause between packets (default 3 seconds)"
1214//usage:     "\n    -A N        Wait N seconds (default 20) after failure"
1215//usage:     "\n    -f      Run in foreground"
1216//usage:    USE_FOR_MMU(
1217//usage:     "\n    -b      Background if lease is not obtained"
1218//usage:    )
1219//usage:     "\n    -n      Exit if lease is not obtained"
1220//usage:     "\n    -q      Exit after obtaining lease"
1221//usage:     "\n    -R      Release IP on exit"
1222//usage:     "\n    -S      Log to syslog too"
1223//usage:    IF_FEATURE_UDHCP_PORT(
1224//usage:     "\n    -P N        Use port N (default 68)"
1225//usage:    )
1226//usage:    IF_FEATURE_UDHCPC_ARPING(
1227//usage:     "\n    -a      Use arping to validate offered address"
1228//usage:    )
1229//usage:     "\n    -O OPT      Request option OPT from server (cumulative)"
1230//usage:     "\n    -o      Don't request any options (unless -O is given)"
1231//usage:     "\n    -r IP       Request this IP address"
1232//usage:     "\n    -x OPT:VAL  Include option OPT in sent packets (cumulative)"
1233//usage:     "\n            Examples of string, numeric, and hex byte opts:"
1234//usage:     "\n            -x hostname:bbox - option 12"
1235//usage:     "\n            -x lease:3600 - option 51 (lease time)"
1236//usage:     "\n            -x 0x3d:0100BEEFC0FFEE - option 61 (client id)"
1237//usage:     "\n    -F NAME     Ask server to update DNS mapping for NAME"
1238//usage:     "\n    -V VENDOR   Vendor identifier (default 'udhcp VERSION')"
1239//usage:     "\n    -C      Don't send MAC as client identifier"
1240//usage:    IF_UDHCP_VERBOSE(
1241//usage:     "\n    -v      Verbose"
1242//usage:    )
1243//usage:    )
1244//usage:     "\nSignals:"
1245//usage:     "\n    USR1    Renew lease"
1246//usage:     "\n    USR2    Release lease"
1247
1248
1249int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1250int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1251{
1252    uint8_t *temp, *message;
1253    const char *str_V, *str_h, *str_F, *str_r;
1254    IF_FEATURE_UDHCP_PORT(char *str_P;)
1255    void *clientid_mac_ptr;
1256    llist_t *list_O = NULL;
1257    llist_t *list_x = NULL;
1258    int tryagain_timeout = 20;
1259    int discover_timeout = 3;
1260    int discover_retries = 3;
1261    uint32_t server_addr = server_addr; /* for compiler */
1262    uint32_t requested_ip = 0;
1263    uint32_t xid = xid; /* for compiler */
1264    int packet_num;
1265    int timeout; /* must be signed */
1266    unsigned already_waited_sec;
1267    unsigned opt;
1268    int max_fd;
1269    int retval;
1270    fd_set rfds;
1271
1272    /* Default options */
1273    IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
1274    IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
1275    client_config.interface = "eth0";
1276    client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
1277    str_V = "udhcp "BB_VER;
1278
1279    /* Parse command line */
1280    /* O,x: list; -T,-t,-A take numeric param */
1281    opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ;
1282    IF_LONG_OPTS(applet_long_options = udhcpc_longopts;)
1283    opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB"
1284        USE_FOR_MMU("b")
1285        IF_FEATURE_UDHCPC_ARPING("a")
1286        IF_FEATURE_UDHCP_PORT("P:")
1287        "v"
1288        , &str_V, &str_h, &str_h, &str_F
1289        , &client_config.interface, &client_config.pidfile, &str_r /* i,p */
1290        , &client_config.script /* s */
1291        , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
1292        , &list_O
1293        , &list_x
1294        IF_FEATURE_UDHCP_PORT(, &str_P)
1295        IF_UDHCP_VERBOSE(, &dhcp_verbose)
1296    );
1297    if (opt & (OPT_h|OPT_H)) {
1298        //msg added 2011-11
1299        bb_error_msg("option -h NAME is deprecated, use -x hostname:NAME");
1300        client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
1301    }
1302    if (opt & OPT_F) {
1303        /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */
1304        client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
1305        /* Flag bits: 0000NEOS
1306         * S: 1 = Client requests server to update A RR in DNS as well as PTR
1307         * O: 1 = Server indicates to client that DNS has been updated regardless
1308         * E: 1 = Name is in DNS format, i.e. <4>host<6>domain<3>com<0>,
1309         *    not "host.domain.com". Format 0 is obsolete.
1310         * N: 1 = Client requests server to not update DNS (S must be 0 then)
1311         * Two [0] bytes which follow are deprecated and must be 0.
1312         */
1313        client_config.fqdn[OPT_DATA + 0] = 0x1;
1314        /*client_config.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */
1315        /*client_config.fqdn[OPT_DATA + 2] = 0; */
1316    }
1317    if (opt & OPT_r)
1318        requested_ip = inet_addr(str_r);
1319#if ENABLE_FEATURE_UDHCP_PORT
1320    if (opt & OPT_P) {
1321        CLIENT_PORT = xatou16(str_P);
1322        SERVER_PORT = CLIENT_PORT - 1;
1323    }
1324#endif
1325    while (list_O) {
1326        char *optstr = llist_pop(&list_O);
1327        unsigned n = bb_strtou(optstr, NULL, 0);
1328        if (errno || n > 254) {
1329            n = udhcp_option_idx(optstr);
1330            n = dhcp_optflags[n].code;
1331        }
1332        client_config.opt_mask[n >> 3] |= 1 << (n & 7);
1333    }
1334    if (!(opt & OPT_o)) {
1335        unsigned i, n;
1336        for (i = 0; (n = dhcp_optflags[i].code) != 0; i++) {
1337            if (dhcp_optflags[i].flags & OPTION_REQ) {
1338                client_config.opt_mask[n >> 3] |= 1 << (n & 7);
1339            }
1340        }
1341    }
1342    while (list_x) {
1343        char *optstr = llist_pop(&list_x);
1344        char *colon = strchr(optstr, ':');
1345        if (colon)
1346            *colon = ' ';
1347        /* now it looks similar to udhcpd's config file line:
1348         * "optname optval", using the common routine: */
1349        udhcp_str2optset(optstr, &client_config.options);
1350    }
1351
1352    if (udhcp_read_interface(client_config.interface,
1353            &client_config.ifindex,
1354            NULL,
1355            client_config.client_mac)
1356    ) {
1357        return 1;
1358    }
1359
1360    clientid_mac_ptr = NULL;
1361    if (!(opt & OPT_C) && !udhcp_find_option(client_config.options, DHCP_CLIENT_ID)) {
1362        /* not suppressed and not set, set the default client ID */
1363        client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
1364        client_config.clientid[OPT_DATA] = 1; /* type: ethernet */
1365        clientid_mac_ptr = client_config.clientid + OPT_DATA+1;
1366        memcpy(clientid_mac_ptr, client_config.client_mac, 6);
1367    }
1368    if (str_V[0] != '\0') {
1369        // can drop -V, str_V, client_config.vendorclass,
1370        // but need to add "vendor" to the list of recognized
1371        // string opts for this to work;
1372        // and need to tweak add_client_options() too...
1373        // ...so the question is, should we?
1374        //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR");
1375        client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
1376    }
1377
1378#if !BB_MMU
1379    /* on NOMMU reexec (i.e., background) early */
1380    if (!(opt & OPT_f)) {
1381        bb_daemonize_or_rexec(0 /* flags */, argv);
1382        logmode = LOGMODE_NONE;
1383    }
1384#endif
1385    if (opt & OPT_S) {
1386        openlog(applet_name, LOG_PID, LOG_DAEMON);
1387        logmode |= LOGMODE_SYSLOG;
1388    }
1389
1390    /* Make sure fd 0,1,2 are open */
1391    bb_sanitize_stdio();
1392    /* Equivalent of doing a fflush after every \n */
1393    setlinebuf(stdout);
1394    /* Create pidfile */
1395    write_pidfile(client_config.pidfile);
1396    /* Goes to stdout (unless NOMMU) and possibly syslog */
1397    bb_info_msg("%s (v"BB_VER") started", applet_name);
1398    /* Set up the signal pipe */
1399    udhcp_sp_setup();
1400    /* We want random_xid to be random... */
1401    srand(monotonic_us());
1402
1403    state = INIT_SELECTING;
1404    udhcp_run_script(NULL, "deconfig");
1405    change_listen_mode(LISTEN_RAW);
1406    packet_num = 0;
1407    timeout = 0;
1408    already_waited_sec = 0;
1409
1410    /* Main event loop. select() waits on signal pipe and possibly
1411     * on sockfd.
1412     * "continue" statements in code below jump to the top of the loop.
1413     */
1414    for (;;) {
1415        struct timeval tv;
1416        struct dhcp_packet packet;
1417        /* silence "uninitialized!" warning */
1418        unsigned timestamp_before_wait = timestamp_before_wait;
1419
1420        //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode);
1421
1422        /* Was opening raw or udp socket here
1423         * if (listen_mode != LISTEN_NONE && sockfd < 0),
1424         * but on fast network renew responses return faster
1425         * than we open sockets. Thus this code is moved
1426         * to change_listen_mode(). Thus we open listen socket
1427         * BEFORE we send renew request (see "case BOUND:"). */
1428
1429        max_fd = udhcp_sp_fd_set(&rfds, sockfd);
1430
1431        tv.tv_sec = timeout - already_waited_sec;
1432        tv.tv_usec = 0;
1433        retval = 0;
1434        /* If we already timed out, fall through with retval = 0, else... */
1435        if ((int)tv.tv_sec > 0) {
1436            log1("Waiting on select %u seconds", (int)tv.tv_sec);
1437            timestamp_before_wait = (unsigned)monotonic_sec();
1438            retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
1439            if (retval < 0) {
1440                /* EINTR? A signal was caught, don't panic */
1441                if (errno == EINTR) {
1442                    already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1443                    continue;
1444                }
1445                /* Else: an error occured, panic! */
1446                bb_perror_msg_and_die("select");
1447            }
1448        }
1449
1450        /* If timeout dropped to zero, time to become active:
1451         * resend discover/renew/whatever
1452         */
1453        if (retval == 0) {
1454            /* When running on a bridge, the ifindex may have changed
1455             * (e.g. if member interfaces were added/removed
1456             * or if the status of the bridge changed).
1457             * Refresh ifindex and client_mac:
1458             */
1459            if (udhcp_read_interface(client_config.interface,
1460                    &client_config.ifindex,
1461                    NULL,
1462                    client_config.client_mac)
1463            ) {
1464                goto ret0; /* iface is gone? */
1465            }
1466            if (clientid_mac_ptr)
1467                memcpy(clientid_mac_ptr, client_config.client_mac, 6);
1468
1469            /* We will restart the wait in any case */
1470            already_waited_sec = 0;
1471
1472            switch (state) {
1473            case INIT_SELECTING:
1474                if (!discover_retries || packet_num < discover_retries) {
1475                    if (packet_num == 0)
1476                        xid = random_xid();
1477                    /* broadcast */
1478                    send_discover(xid, requested_ip);
1479                    timeout = discover_timeout;
1480                    packet_num++;
1481                    continue;
1482                }
1483 leasefail:
1484                udhcp_run_script(NULL, "leasefail");
1485#if BB_MMU /* -b is not supported on NOMMU */
1486                if (opt & OPT_b) { /* background if no lease */
1487                    bb_info_msg("No lease, forking to background");
1488                    client_background();
1489                    /* do not background again! */
1490                    opt = ((opt & ~OPT_b) | OPT_f);
1491                } else
1492#endif
1493                if (opt & OPT_n) { /* abort if no lease */
1494                    bb_info_msg("No lease, failing");
1495                    retval = 1;
1496                    goto ret;
1497                }
1498                /* wait before trying again */
1499                timeout = tryagain_timeout;
1500                packet_num = 0;
1501                continue;
1502            case REQUESTING:
1503                if (!discover_retries || packet_num < discover_retries) {
1504                    /* send broadcast select packet */
1505                    send_select(xid, server_addr, requested_ip);
1506                    timeout = discover_timeout;
1507                    packet_num++;
1508                    continue;
1509                }
1510                /* Timed out, go back to init state.
1511                 * "discover...select...discover..." loops
1512                 * were seen in the wild. Treat them similarly
1513                 * to "no response to discover" case */
1514                change_listen_mode(LISTEN_RAW);
1515                state = INIT_SELECTING;
1516                goto leasefail;
1517            case BOUND:
1518                /* 1/2 lease passed, enter renewing state */
1519                state = RENEWING;
1520                client_config.first_secs = 0; /* make secs field count from 0 */
1521                change_listen_mode(LISTEN_KERNEL);
1522                log1("Entering renew state");
1523                /* fall right through */
1524            case RENEW_REQUESTED: /* manual (SIGUSR1) renew */
1525            case_RENEW_REQUESTED:
1526            case RENEWING:
1527                if (timeout > 60) {
1528                    /* send an unicast renew request */
1529            /* Sometimes observed to fail (EADDRNOTAVAIL) to bind
1530             * a new UDP socket for sending inside send_renew.
1531             * I hazard to guess existing listening socket
1532             * is somehow conflicting with it, but why is it
1533             * not deterministic then?! Strange.
1534             * Anyway, it does recover by eventually failing through
1535             * into INIT_SELECTING state.
1536             */
1537                    send_renew(xid, server_addr, requested_ip);
1538                    timeout >>= 1;
1539                    continue;
1540                }
1541                /* Timed out, enter rebinding state */
1542                log1("Entering rebinding state");
1543                state = REBINDING;
1544                /* fall right through */
1545            case REBINDING:
1546                /* Switch to bcast receive */
1547                change_listen_mode(LISTEN_RAW);
1548                /* Lease is *really* about to run out,
1549                 * try to find DHCP server using broadcast */
1550                if (timeout > 0) {
1551                    /* send a broadcast renew request */
1552                    send_renew(xid, 0 /*INADDR_ANY*/, requested_ip);
1553                    timeout >>= 1;
1554                    continue;
1555                }
1556                /* Timed out, enter init state */
1557                bb_info_msg("Lease lost, entering init state");
1558                udhcp_run_script(NULL, "deconfig");
1559                state = INIT_SELECTING;
1560                client_config.first_secs = 0; /* make secs field count from 0 */
1561                /*timeout = 0; - already is */
1562                packet_num = 0;
1563                continue;
1564            /* case RELEASED: */
1565            }
1566            /* yah, I know, *you* say it would never happen */
1567            timeout = INT_MAX;
1568            continue; /* back to main loop */
1569        } /* if select timed out */
1570
1571        /* select() didn't timeout, something happened */
1572
1573        /* Is it a signal? */
1574        /* note: udhcp_sp_read checks FD_ISSET before reading */
1575        switch (udhcp_sp_read(&rfds)) {
1576        case SIGUSR1:
1577            client_config.first_secs = 0; /* make secs field count from 0 */
1578            already_waited_sec = 0;
1579            perform_renew();
1580            if (state == RENEW_REQUESTED) {
1581                /* We might be either on the same network
1582                 * (in which case renew might work),
1583                 * or we might be on a completely different one
1584                 * (in which case renew won't ever succeed).
1585                 * For the second case, must make sure timeout
1586                 * is not too big, or else we can send
1587                 * futile renew requests for hours.
1588                 * (Ab)use -A TIMEOUT value (usually 20 sec)
1589                 * as a cap on the timeout.
1590                 */
1591                if (timeout > tryagain_timeout)
1592                    timeout = tryagain_timeout;
1593                goto case_RENEW_REQUESTED;
1594            }
1595            /* Start things over */
1596            packet_num = 0;
1597            /* Kill any timeouts, user wants this to hurry along */
1598            timeout = 0;
1599            continue;
1600        case SIGUSR2:
1601            perform_release(server_addr, requested_ip);
1602            timeout = INT_MAX;
1603            continue;
1604        case SIGTERM:
1605            bb_info_msg("Received SIGTERM");
1606            goto ret0;
1607        }
1608
1609        /* Is it a packet? */
1610        if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds))
1611            continue; /* no */
1612
1613        {
1614            int len;
1615
1616            /* A packet is ready, read it */
1617            if (listen_mode == LISTEN_KERNEL)
1618                len = udhcp_recv_kernel_packet(&packet, sockfd);
1619            else
1620                len = udhcp_recv_raw_packet(&packet, sockfd);
1621            if (len == -1) {
1622                /* Error is severe, reopen socket */
1623                bb_info_msg("Read error: %s, reopening socket", strerror(errno));
1624                sleep(discover_timeout); /* 3 seconds by default */
1625                change_listen_mode(listen_mode); /* just close and reopen */
1626            }
1627            /* If this packet will turn out to be unrelated/bogus,
1628             * we will go back and wait for next one.
1629             * Be sure timeout is properly decreased. */
1630            already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait;
1631            if (len < 0)
1632                continue;
1633        }
1634
1635        if (packet.xid != xid) {
1636            log1("xid %x (our is %x), ignoring packet",
1637                (unsigned)packet.xid, (unsigned)xid);
1638            continue;
1639        }
1640
1641        /* Ignore packets that aren't for us */
1642        if (packet.hlen != 6
1643         || memcmp(packet.chaddr, client_config.client_mac, 6) != 0
1644        ) {
1645//FIXME: need to also check that last 10 bytes are zero
1646            log1("chaddr does not match, ignoring packet"); // log2?
1647            continue;
1648        }
1649
1650        message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
1651        if (message == NULL) {
1652            bb_error_msg("no message type option, ignoring packet");
1653            continue;
1654        }
1655
1656        switch (state) {
1657        case INIT_SELECTING:
1658            /* Must be a DHCPOFFER */
1659            if (*message == DHCPOFFER) {
1660/* What exactly is server's IP? There are several values.
1661 * Example DHCP offer captured with tchdump:
1662 *
1663 * 10.34.25.254:67 > 10.34.25.202:68 // IP header's src
1664 * BOOTP fields:
1665 * Your-IP 10.34.25.202
1666 * Server-IP 10.34.32.125   // "next server" IP
1667 * Gateway-IP 10.34.25.254  // relay's address (if DHCP relays are in use)
1668 * DHCP options:
1669 * DHCP-Message Option 53, length 1: Offer
1670 * Server-ID Option 54, length 4: 10.34.255.7       // "server ID"
1671 * Default-Gateway Option 3, length 4: 10.34.25.254 // router
1672 *
1673 * We think that real server IP (one to use in renew/release)
1674 * is one in Server-ID option. But I am not 100% sure.
1675 * IP header's src and Gateway-IP (same in this example)
1676 * might work too.
1677 * "Next server" and router are definitely wrong ones to use, though...
1678 */
1679                temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
1680                if (!temp) {
1681                    bb_error_msg("no server ID, ignoring packet");
1682                    continue;
1683                    /* still selecting - this server looks bad */
1684                }
1685                /* it IS unaligned sometimes, don't "optimize" */
1686                move_from_unaligned32(server_addr, temp);
1687                /*xid = packet.xid; - already is */
1688                requested_ip = packet.yiaddr;
1689
1690                /* enter requesting state */
1691                state = REQUESTING;
1692                timeout = 0;
1693                packet_num = 0;
1694                already_waited_sec = 0;
1695            }
1696            continue;
1697        case REQUESTING:
1698        case RENEWING:
1699        case RENEW_REQUESTED:
1700        case REBINDING:
1701            if (*message == DHCPACK) {
1702                uint32_t lease_seconds;
1703                struct in_addr temp_addr;
1704
1705                temp = udhcp_get_option(&packet, DHCP_LEASE_TIME);
1706                if (!temp) {
1707                    bb_error_msg("no lease time with ACK, using 1 hour lease");
1708                    lease_seconds = 60 * 60;
1709                } else {
1710                    /* it IS unaligned sometimes, don't "optimize" */
1711                    move_from_unaligned32(lease_seconds, temp);
1712                    lease_seconds = ntohl(lease_seconds);
1713                    /* paranoia: must not be too small and not prone to overflows */
1714                    if (lease_seconds < 0x10)
1715                        lease_seconds = 0x10;
1716                    if (lease_seconds >= 0x10000000)
1717                        lease_seconds = 0x0fffffff;
1718                }
1719#if ENABLE_FEATURE_UDHCPC_ARPING
1720                if (opt & OPT_a) {
1721/* RFC 2131 3.1 paragraph 5:
1722 * "The client receives the DHCPACK message with configuration
1723 * parameters. The client SHOULD perform a final check on the
1724 * parameters (e.g., ARP for allocated network address), and notes
1725 * the duration of the lease specified in the DHCPACK message. At this
1726 * point, the client is configured. If the client detects that the
1727 * address is already in use (e.g., through the use of ARP),
1728 * the client MUST send a DHCPDECLINE message to the server and restarts
1729 * the configuration process..." */
1730                    if (!arpping(packet.yiaddr,
1731                            NULL,
1732                            (uint32_t) 0,
1733                            client_config.client_mac,
1734                            client_config.interface)
1735                    ) {
1736                        bb_info_msg("Offered address is in use "
1737                            "(got ARP reply), declining");
1738                        send_decline(/*xid,*/ server_addr, packet.yiaddr);
1739
1740                        if (state != REQUESTING)
1741                            udhcp_run_script(NULL, "deconfig");
1742                        change_listen_mode(LISTEN_RAW);
1743                        state = INIT_SELECTING;
1744                        client_config.first_secs = 0; /* make secs field count from 0 */
1745                        requested_ip = 0;
1746                        timeout = tryagain_timeout;
1747                        packet_num = 0;
1748                        already_waited_sec = 0;
1749                        continue; /* back to main loop */
1750                    }
1751                }
1752#endif
1753                /* enter bound state */
1754                timeout = lease_seconds / 2;
1755                temp_addr.s_addr = packet.yiaddr;
1756                bb_info_msg("Lease of %s obtained, lease time %u",
1757                    inet_ntoa(temp_addr), (unsigned)lease_seconds);
1758                requested_ip = packet.yiaddr;
1759                udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew");
1760
1761                state = BOUND;
1762                change_listen_mode(LISTEN_NONE);
1763                if (opt & OPT_q) { /* quit after lease */
1764                    goto ret0;
1765                }
1766                /* future renew failures should not exit (JM) */
1767                opt &= ~OPT_n;
1768#if BB_MMU /* NOMMU case backgrounded earlier */
1769                if (!(opt & OPT_f)) {
1770                    client_background();
1771                    /* do not background again! */
1772                    opt = ((opt & ~OPT_b) | OPT_f);
1773                }
1774#endif
1775                /* make future renew packets use different xid */
1776                /* xid = random_xid(); ...but why bother? */
1777                already_waited_sec = 0;
1778                continue; /* back to main loop */
1779            }
1780            if (*message == DHCPNAK) {
1781                /* return to init state */
1782                bb_info_msg("Received DHCP NAK");
1783                udhcp_run_script(&packet, "nak");
1784                if (state != REQUESTING)
1785                    udhcp_run_script(NULL, "deconfig");
1786                change_listen_mode(LISTEN_RAW);
1787                sleep(3); /* avoid excessive network traffic */
1788                state = INIT_SELECTING;
1789                client_config.first_secs = 0; /* make secs field count from 0 */
1790                requested_ip = 0;
1791                timeout = 0;
1792                packet_num = 0;
1793                already_waited_sec = 0;
1794            }
1795            continue;
1796        /* case BOUND: - ignore all packets */
1797        /* case RELEASED: - ignore all packets */
1798        }
1799        /* back to main loop */
1800    } /* for (;;) - main loop ends */
1801
1802 ret0:
1803    if (opt & OPT_R) /* release on quit */
1804        perform_release(server_addr, requested_ip);
1805    retval = 0;
1806 ret:
1807    /*if (client_config.pidfile) - remove_pidfile has its own check */
1808        remove_pidfile(client_config.pidfile);
1809    return retval;
1810}
Note: See TracBrowser for help on using the repository browser.