source: branches/2.2.9/mindi-busybox/networking/udhcp/dhcpc.c @ 2725

Last change on this file since 2725 was 2725, checked in by Bruno Cornec, 9 years ago
  • 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 size: 45.9 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) || 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.
424 */
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
668static int sockfd = -1;
669
670#define LISTEN_NONE   0
671#define LISTEN_KERNEL 1
672#define LISTEN_RAW    2
673static smallint listen_mode;
674
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
689static smallint state;
690
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;
771    if (sockfd >= 0) {
772        close(sockfd);
773        sockfd = -1;
774    }
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
782static void perform_renew(void)
783{
784    bb_info_msg("Performing a DHCP renew");
785    switch (state) {
786    case BOUND:
787        change_listen_mode(LISTEN_KERNEL);
788    case RENEWING:
789    case REBINDING:
790        state = RENEW_REQUESTED;
791        break;
792    case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
793        udhcp_run_script(NULL, "deconfig");
794    case REQUESTING:
795    case RELEASED:
796        change_listen_mode(LISTEN_RAW);
797        state = INIT_SELECTING;
798        break;
799    case INIT_SELECTING:
800        break;
801    }
802}
803
804static void perform_release(uint32_t requested_ip, uint32_t server_addr)
805{
806    char buffer[sizeof("255.255.255.255")];
807    struct in_addr temp_addr;
808
809    /* send release packet */
810    if (state == BOUND || state == RENEWING || state == REBINDING) {
811        temp_addr.s_addr = server_addr;
812        strcpy(buffer, inet_ntoa(temp_addr));
813        temp_addr.s_addr = requested_ip;
814        bb_info_msg("Unicasting a release of %s to %s",
815                inet_ntoa(temp_addr), buffer);
816        send_release(server_addr, requested_ip); /* unicast */
817        udhcp_run_script(NULL, "deconfig");
818    }
819    bb_info_msg("Entering released state");
820
821    change_listen_mode(LISTEN_NONE);
822    state = RELEASED;
823}
824
825static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
826{
827    uint8_t *storage;
828    int len = strnlen(str, 255);
829    storage = xzalloc(len + extra + OPT_DATA);
830    storage[OPT_CODE] = code;
831    storage[OPT_LEN] = len + extra;
832    memcpy(storage + extra + OPT_DATA, str, len);
833    return storage;
834}
835
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)
932{
933    uint8_t *temp, *message;
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;
944    uint32_t xid = 0;
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;
949    unsigned opt;
950    int max_fd;
951    int retval;
952    struct timeval tv;
953    struct dhcp_packet packet;
954    fd_set rfds;
955
956#if ENABLE_LONG_OPTS
957    static const char udhcpc_longopts[] ALIGN1 =
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")
980        ;
981#endif
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;)
1016    client_config.interface = "eth0";
1017    client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
1018    str_V = "udhcp "BB_VER;
1019
1020    /* Parse command line */
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"
1025#endif
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
1043        );
1044    if (opt & (OPT_h|OPT_H))
1045        client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
1046    if (opt & OPT_F) {
1047        /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */
1048        client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
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         */
1057        client_config.fqdn[OPT_DATA + 0] = 0x1;
1058        /*client_config.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */
1059        /*client_config.fqdn[OPT_DATA + 2] = 0; */
1060    }
1061    if (opt & OPT_r)
1062        requested_ip = inet_addr(str_r);
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
1112    if (opt & OPT_S) {
1113        openlog(applet_name, LOG_PID, LOG_DAEMON);
1114        logmode |= LOGMODE_SYSLOG;
1115    }
1116
1117    /* Make sure fd 0,1,2 are open */
1118    bb_sanitize_stdio();
1119    /* Equivalent of doing a fflush after every \n */
1120    setlinebuf(stdout);
1121    /* Create pidfile */
1122    write_pidfile(client_config.pidfile);
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 */
1126    udhcp_sp_setup();
1127    /* We want random_xid to be random... */
1128    srand(monotonic_us());
1129
1130    state = INIT_SELECTING;
1131    udhcp_run_script(NULL, "deconfig");
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     */
1141    for (;;) {
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;
1157        tv.tv_usec = 0;
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...");
1163            retval = select(max_fd + 1, &rfds, NULL, NULL, &tv);
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                }
1170                /* Else: an error occured, panic! */
1171                bb_perror_msg_and_die("select");
1172            }
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
1197            switch (state) {
1198            case INIT_SELECTING:
1199                if (packet_num < discover_retries) {
1200                    if (packet_num == 0)
1201                        xid = random_xid();
1202                    /* broadcast */
1203                    send_discover(xid, requested_ip);
1204                    timeout = discover_timeout;
1205                    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;
1398                } else {
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;
1405                }
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;
1433                        packet_num = 0;
1434                        already_waited_sec = 0;
1435                        continue; /* back to main loop */
1436                    }
1437                }
1438#endif
1439                /* enter bound state */
1440                timeout = lease_seconds / 2;
1441                {
1442                    struct in_addr temp_addr;
1443                    temp_addr.s_addr = packet.yiaddr;
1444                    bb_info_msg("Lease of %s obtained, lease time %u",
1445                        inet_ntoa(temp_addr), (unsigned)lease_seconds);
1446                }
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 */
1468            }
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;
1482            }
1483            continue;
1484        /* case BOUND: - ignore all packets */
1485        /* case RELEASED: - ignore all packets */
1486        }
1487        /* back to main loop */
1488    } /* for (;;) - main loop ends */
1489
1490 ret0:
1491    retval = 0;
1492 ret:
1493    /*if (client_config.pidfile) - remove_pidfile has its own check */
1494        remove_pidfile(client_config.pidfile);
1495    return retval;
1496}
Note: See TracBrowser for help on using the repository browser.