Ignore:
Timestamp:
Feb 25, 2011, 9:26:54 PM (13 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.18.3 to avoid problems with the tar command which is now failing on recent versions with busybox 1.7.3
Location:
branches/2.2.9/mindi-busybox/networking/udhcp
Files:
2 added
18 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.9/mindi-busybox/networking/udhcp/Config.in

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Config.src
    12#
    23# For a description of the syntax of this configuration file,
     
    45#
    56
    6 config APP_UDHCPD
    7     bool "udhcp Server (udhcpd)"
    8     default n
     7
     8
     9config UDHCPD
     10    bool "udhcp server (udhcpd)"
     11    default y
     12    depends on PLATFORM_LINUX
    913    help
    10       uDHCPd is a DHCP server geared primarily toward embedded systems,
     14      udhcpd is a DHCP server geared primarily toward embedded systems,
    1115      while striving to be fully functional and RFC compliant.
    1216
    13       See http://udhcp.busybox.net for further details.
    14 
    15 config APP_DHCPRELAY
     17config DHCPRELAY
    1618    bool "dhcprelay"
    17     default n
    18     depends on APP_UDHCPD
     19    default y
     20    depends on UDHCPD
    1921    help
    2022      dhcprelay listens for dhcp requests on one or more interfaces
     
    2224      server.
    2325
    24 config APP_DUMPLEASES
     26config DUMPLEASES
    2527    bool "Lease display utility (dumpleases)"
    26     default n
    27     depends on APP_UDHCPD
     28    default y
     29    depends on UDHCPD
    2830    help
    2931      dumpleases displays the leases written out by the udhcpd server.
     
    3133      by the absolute time that it expires in seconds from epoch.
    3234
    33       See http://udhcp.busybox.net for further details.
    34 
    3535config FEATURE_UDHCPD_WRITE_LEASES_EARLY
    3636    bool "Rewrite the lease file at every new acknowledge"
    37     default n
    38     depends on APP_UDHCPD
     37    default y
     38    depends on UDHCPD
    3939    help
    4040      If selected, udhcpd will write a new file with leases every
    41       time a new lease has been accepted, thus eleminating the need
    42       to send SIGUSR1 for the initial writing, or updating. Any timed
     41      time a new lease has been accepted, thus eliminating the need
     42      to send SIGUSR1 for the initial writing or updating. Any timed
    4343      rewriting remains undisturbed
    4444
    45 config APP_UDHCPC
    46     bool "udhcp Client (udhcpc)"
    47     default n
     45config DHCPD_LEASES_FILE
     46    string "Absolute path to lease file"
     47    default "/var/lib/misc/udhcpd.leases"
     48    depends on UDHCPD
    4849    help
    49       uDHCPc is a DHCP client geared primarily toward embedded systems,
     50      udhcpd stores addresses in a lease file. This is the absolute path
     51      of the file. Normally it is safe to leave it untouched.
     52
     53config UDHCPC
     54    bool "udhcp client (udhcpc)"
     55    default y
     56    depends on PLATFORM_LINUX
     57    help
     58      udhcpc is a DHCP client geared primarily toward embedded systems,
    5059      while striving to be fully functional and RFC compliant.
    5160
    5261      The udhcp client negotiates a lease with the DHCP server and
    53       notifies a set of scripts when a lease is obtained or lost.
     62      runs a script when a lease is obtained or lost.
    5463
    55       See http://udhcp.busybox.net for further details.
     64config FEATURE_UDHCPC_ARPING
     65    bool "Verify that the offered address is free, using ARP ping"
     66    default y
     67    depends on UDHCPC
     68    help
     69      If selected, udhcpc will send ARP probes and make sure
     70      the offered address is really not in use by anyone. The client
     71      will DHCPDECLINE the offer if the address is in use,
     72      and restart the discover process.
    5673
    57 config FEATURE_UDHCP_DEBUG
    58     bool "Compile udhcp with noisy debugging messages"
    59     default n
    60     depends on APP_UDHCPD || APP_UDHCPC
     74config FEATURE_UDHCP_PORT
     75    bool "Enable '-P port' option for udhcpd and udhcpc"
     76    default y
     77    depends on UDHCPD || UDHCPC
    6178    help
    62       If selected, udhcpd will output extra debugging output.  If using
    63       this option, compile uDHCP with "-g", and do not fork the daemon to
    64       the background.
     79      At the cost of ~300 bytes, enables -P port option.
     80      This feature is typically not needed.
    6581
    66       See http://udhcp.busybox.net for further details.
     82config UDHCP_DEBUG
     83    int "Maximum verbosity level for udhcp applets (0..9)"
     84    default 9
     85    range 0 9
     86    depends on UDHCPD || UDHCPC || DHCPRELAY
     87    help
     88      Verbosity can be increased with multiple -v options.
     89      This option controls how high it can be cranked up.
    6790
    68 config FEATURE_RFC3397
     91      Bigger values result in bigger code. Levels above 1
     92      are very verbose and useful for debugging only.
     93
     94config FEATURE_UDHCP_RFC3397
    6995    bool "Support for RFC3397 domain search (experimental)"
    70     default n
    71     depends on APP_UDHCPD || APP_UDHCPC
     96    default y
     97    depends on UDHCPD || UDHCPC
    7298    help
    7399      If selected, both client and server will support passing of domain
    74       search lists via option 119, specified in RFC3397.
     100      search lists via option 119, specified in RFC 3397,
     101      and SIP servers option 120, specified in RFC 3361.
     102
     103config UDHCPC_DEFAULT_SCRIPT
     104    string "Absolute path to config script"
     105    default "/usr/share/udhcpc/default.script"
     106    depends on UDHCPC
     107    help
     108      This script is called after udhcpc receives an answer. See
     109      examples/udhcp for a working example. Normally it is safe
     110      to leave this untouched.
     111
     112config UDHCPC_SLACK_FOR_BUGGY_SERVERS
     113    int "DHCP options slack buffer size"
     114    default 80
     115    range 0 924
     116    depends on UDHCPD || UDHCPC
     117    help
     118      Some buggy DHCP servers send DHCP offer packets with option
     119      field larger than we expect (which might also be considered a
     120      buffer overflow attempt). These packets are normally discarded.
     121      If circumstances beyond your control force you to support such
     122      servers, this may help. The upper limit (924) makes dhcpc accept
     123      even 1500 byte packets (maximum-sized ethernet packets).
     124
     125      This option does not make dhcp[cd] emit non-standard
     126      sized packets.
     127
     128      Known buggy DHCP servers:
     129      3Com OfficeConnect Remote 812 ADSL Router:
     130        seems to confuse maximum allowed UDP packet size with
     131        maximum size of entire IP packet, and sends packets which are
     132        28 bytes too large.
     133      Seednet (ISP) VDSL: sends packets 2 bytes too large.
  • branches/2.2.9/mindi-busybox/networking/udhcp/Kbuild

    r1765 r2725  
     1# DO NOT EDIT. This file is generated from Kbuild.src
    12# Makefile for busybox
    23#
    34# Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
    45#
    5 # Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     6# Licensed under GPLv2 or later, see file LICENSE in this source tree.
    67#
    78
    89lib-y:=
    9 lib-$(CONFIG_APP_UDHCPC)        += common.o options.o packet.o \
    10                                    signalpipe.o socket.o
    11 lib-$(CONFIG_APP_UDHCPD)        += common.o options.o packet.o \
    12                                    signalpipe.o socket.o
    13 lib-$(CONFIG_APP_UDHCPC)        += dhcpc.o clientpacket.o clientsocket.o \
    14                                    script.o
    15 lib-$(CONFIG_APP_UDHCPD)        += dhcpd.o arpping.o files.o leases.o \
    16                                    serverpacket.o static_leases.o
    17 lib-$(CONFIG_APP_DUMPLEASES)    += dumpleases.o
    18 lib-$(CONFIG_APP_DHCPRELAY)     += dhcprelay.o
    19 lib-$(CONFIG_FEATURE_RFC3397)   += domain_codec.o
     10
     11
     12
     13lib-$(CONFIG_UDHCPC)     += common.o packet.o signalpipe.o socket.o
     14lib-$(CONFIG_UDHCPD)     += common.o packet.o signalpipe.o socket.o
     15
     16lib-$(CONFIG_UDHCPC)     += dhcpc.o
     17lib-$(CONFIG_UDHCPD)     += dhcpd.o arpping.o files.o leases.o static_leases.o
     18lib-$(CONFIG_DUMPLEASES) += dumpleases.o
     19lib-$(CONFIG_DHCPRELAY)  += dhcprelay.o
     20
     21lib-$(CONFIG_FEATURE_UDHCPC_ARPING) += arpping.o
     22lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o
  • branches/2.2.9/mindi-busybox/networking/udhcp/arpping.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * arpping.c
    4  *
    53 * Mostly stolen from: dhcpcd - DHCP client daemon
    64 * by Yoichi Hariguchi <yoichi@fore.com>
     5 *
     6 * Licensed under GPLv2, see file LICENSE in this source tree.
    77 */
    8 
    98#include <netinet/if_ether.h>
    109#include <net/if_arp.h>
     
    1211#include "common.h"
    1312#include "dhcpd.h"
    14 
    1513
    1614struct arpMsg {
     
    3129    uint8_t  tInaddr[4];    /* 26 target's IP address */
    3230    uint8_t  pad[18];       /* 2a pad for min. ethernet payload (60 bytes) */
    33 } ATTRIBUTE_PACKED;
     31} PACKED;
    3432
     33enum {
     34    ARP_MSG_SIZE = 0x2a
     35};
    3536
    3637/* Returns 1 if no reply received */
    37 
    38 int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface)
     38int FAST_FUNC arpping(uint32_t test_nip,
     39        const uint8_t *safe_mac,
     40        uint32_t from_ip,
     41        uint8_t *from_mac,
     42        const char *interface)
    3943{
    40     int timeout = 2;
    41     int s;                  /* socket */
     44    int timeout_ms;
     45    struct pollfd pfd[1];
     46#define s (pfd[0].fd)           /* socket */
    4247    int rv = 1;             /* "no reply received" yet */
    4348    struct sockaddr addr;   /* for interface name */
    4449    struct arpMsg arp;
    45     fd_set fdset;
    46     struct timeval tm;
    47     unsigned prevTime;
    4850
    4951    s = socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ARP));
     
    5456
    5557    if (setsockopt_broadcast(s) == -1) {
    56         bb_perror_msg("cannot setsocketopt on raw socket");
     58        bb_perror_msg("can't enable bcast on raw socket");
    5759        goto ret;
    5860    }
     
    7072    memcpy(arp.sHaddr, from_mac, 6);                /* source hardware address */
    7173    memcpy(arp.sInaddr, &from_ip, sizeof(from_ip)); /* source IP address */
    72     /* tHaddr */                                    /* target hardware address */
    73     memcpy(arp.tInaddr, &test_ip, sizeof(test_ip)); /* target IP address */
     74    /* tHaddr is zero-filled */                     /* target hardware address */
     75    memcpy(arp.tInaddr, &test_nip, sizeof(test_nip));/* target IP address */
    7476
    7577    memset(&addr, 0, sizeof(addr));
    7678    safe_strncpy(addr.sa_data, interface, sizeof(addr.sa_data));
    77     if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0)
     79    if (sendto(s, &arp, sizeof(arp), 0, &addr, sizeof(addr)) < 0) {
     80        // TODO: error message? caller didn't expect us to fail,
     81        // just returning 1 "no reply received" misleads it.
    7882        goto ret;
     83    }
    7984
    8085    /* wait for arp reply, and check it */
     86    timeout_ms = 2000;
    8187    do {
     88        typedef uint32_t aliased_uint32_t FIX_ALIASING;
    8289        int r;
    83         prevTime = monotonic_sec();
    84         FD_ZERO(&fdset);
    85         FD_SET(s, &fdset);
    86         tm.tv_sec = timeout;
    87         tm.tv_usec = 0;
    88         r = select(s + 1, &fdset, NULL, NULL, &tm);
    89         if (r < 0) {
    90             bb_perror_msg("error on ARPING request");
    91             if (errno != EINTR)
     90        unsigned prevTime = monotonic_ms();
     91
     92        pfd[0].events = POLLIN;
     93        r = safe_poll(pfd, 1, timeout_ms);
     94        if (r < 0)
     95            break;
     96        if (r) {
     97            r = safe_read(s, &arp, sizeof(arp));
     98            if (r < 0)
    9299                break;
    93         } else if (r) {
    94             if (recv(s, &arp, sizeof(arp), 0) < 0)
    95                 break;
    96             if (arp.operation == htons(ARPOP_REPLY)
    97              && memcmp(arp.tHaddr, from_mac, 6) == 0
    98              && *((uint32_t *) arp.sInaddr) == test_ip
     100
     101            //log3("sHaddr %02x:%02x:%02x:%02x:%02x:%02x",
     102            //  arp.sHaddr[0], arp.sHaddr[1], arp.sHaddr[2],
     103            //  arp.sHaddr[3], arp.sHaddr[4], arp.sHaddr[5]);
     104
     105            if (r >= ARP_MSG_SIZE
     106             && arp.operation == htons(ARPOP_REPLY)
     107             /* don't check it: Linux doesn't return proper tHaddr (fixed in 2.6.24?) */
     108             /* && memcmp(arp.tHaddr, from_mac, 6) == 0 */
     109             && *(aliased_uint32_t*)arp.sInaddr == test_nip
    99110            ) {
    100                 rv = 0;
     111                /* if ARP source MAC matches safe_mac
     112                 * (which is client's MAC), then it's not a conflict
     113                 * (client simply already has this IP and replies to ARPs!)
     114                 */
     115                if (!safe_mac || memcmp(safe_mac, arp.sHaddr, 6) != 0)
     116                    rv = 0;
     117                //else log2("sHaddr == safe_mac");
    101118                break;
    102119            }
    103120        }
    104         timeout -= monotonic_sec() - prevTime;
    105     } while (timeout > 0);
     121        timeout_ms -= (unsigned)monotonic_ms() - prevTime;
     122    } while (timeout_ms > 0);
    106123
    107124 ret:
    108125    close(s);
    109     DEBUG("%srp reply received for this address", rv ? "No a" : "A");
     126    log1("%srp reply received for this address", rv ? "No a" : "A");
    110127    return rv;
    111128}
  • branches/2.2.9/mindi-busybox/networking/udhcp/common.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* common.c
     2/*
     3 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
    34 *
    4  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     5 * Licensed under GPLv2, see file LICENSE in this source tree.
    56 */
    6 
    77#include "common.h"
     8
     9#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     10unsigned dhcp_verbose;
     11#endif
    812
    913const uint8_t MAC_BCAST_ADDR[6] ALIGN2 = {
    1014    0xff, 0xff, 0xff, 0xff, 0xff, 0xff
    1115};
     16
     17/* Supported options are easily added here.
     18 * See RFC2132 for more options.
     19 * OPTION_REQ: these options are requested by udhcpc (unless -o).
     20 */
     21const struct dhcp_optflag dhcp_optflags[] = {
     22    /* flags                                    code */
     23    { OPTION_IP                   | OPTION_REQ, 0x01 }, /* DHCP_SUBNET        */
     24    { OPTION_S32                              , 0x02 }, /* DHCP_TIME_OFFSET   */
     25    { OPTION_IP | OPTION_LIST     | OPTION_REQ, 0x03 }, /* DHCP_ROUTER        */
     26//  { OPTION_IP | OPTION_LIST                 , 0x04 }, /* DHCP_TIME_SERVER   */
     27//  { OPTION_IP | OPTION_LIST                 , 0x05 }, /* DHCP_NAME_SERVER   */
     28    { OPTION_IP | OPTION_LIST     | OPTION_REQ, 0x06 }, /* DHCP_DNS_SERVER    */
     29//  { OPTION_IP | OPTION_LIST                 , 0x07 }, /* DHCP_LOG_SERVER    */
     30//  { OPTION_IP | OPTION_LIST                 , 0x08 }, /* DHCP_COOKIE_SERVER */
     31    { OPTION_IP | OPTION_LIST                 , 0x09 }, /* DHCP_LPR_SERVER    */
     32    { OPTION_STRING               | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME     */
     33    { OPTION_U16                              , 0x0d }, /* DHCP_BOOT_SIZE     */
     34    { OPTION_STRING               | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME   */
     35    { OPTION_IP                               , 0x10 }, /* DHCP_SWAP_SERVER   */
     36    { OPTION_STRING                           , 0x11 }, /* DHCP_ROOT_PATH     */
     37    { OPTION_U8                               , 0x17 }, /* DHCP_IP_TTL        */
     38    { OPTION_U16                              , 0x1a }, /* DHCP_MTU           */
     39    { OPTION_IP                   | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST     */
     40    { OPTION_IP_PAIR | OPTION_LIST            , 0x21 }, /* DHCP_ROUTES        */
     41    { OPTION_STRING                           , 0x28 }, /* DHCP_NIS_DOMAIN    */
     42    { OPTION_IP | OPTION_LIST                 , 0x29 }, /* DHCP_NIS_SERVER    */
     43    { OPTION_IP | OPTION_LIST     | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER    */
     44    { OPTION_IP | OPTION_LIST                 , 0x2c }, /* DHCP_WINS_SERVER   */
     45    { OPTION_U32                              , 0x33 }, /* DHCP_LEASE_TIME    */
     46    { OPTION_IP                               , 0x36 }, /* DHCP_SERVER_ID     */
     47    { OPTION_STRING                           , 0x38 }, /* DHCP_ERR_MESSAGE   */
     48//TODO: must be combined with 'sname' and 'file' handling:
     49    { OPTION_STRING                           , 0x42 }, /* DHCP_TFTP_SERVER_NAME */
     50    { OPTION_STRING                           , 0x43 }, /* DHCP_BOOT_FILE     */
     51//TODO: not a string, but a set of LASCII strings:
     52//  { OPTION_STRING                           , 0x4D }, /* DHCP_USER_CLASS    */
     53#if ENABLE_FEATURE_UDHCP_RFC3397
     54    { OPTION_DNS_STRING | OPTION_LIST         , 0x77 }, /* DHCP_DOMAIN_SEARCH */
     55    { OPTION_SIP_SERVERS                      , 0x78 }, /* DHCP_SIP_SERVERS   */
     56#endif
     57    { OPTION_STATIC_ROUTES                    , 0x79 }, /* DHCP_STATIC_ROUTES */
     58    { OPTION_STATIC_ROUTES                    , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */
     59    { OPTION_STRING                           , 0xfc }, /* DHCP_WPAD          */
     60
     61    /* Options below have no match in dhcp_option_strings[],
     62     * are not passed to dhcpc scripts, and cannot be specified
     63     * with "option XXX YYY" syntax in dhcpd config file.
     64     * These entries are only used internally by udhcp[cd]
     65     * to correctly encode options into packets.
     66     */
     67
     68    { OPTION_IP                               , 0x32 }, /* DHCP_REQUESTED_IP  */
     69    { OPTION_U8                               , 0x35 }, /* DHCP_MESSAGE_TYPE  */
     70    { OPTION_U16                              , 0x39 }, /* DHCP_MAX_SIZE      */
     71//looks like these opts will work just fine even without these defs:
     72//  { OPTION_STRING                           , 0x3c }, /* DHCP_VENDOR        */
     73//  /* not really a string: */
     74//  { OPTION_STRING                           , 0x3d }, /* DHCP_CLIENT_ID     */
     75    { 0, 0 } /* zeroed terminating entry */
     76};
     77
     78/* Used for converting options from incoming packets to env variables
     79 * for udhcpc stript, and for setting options for udhcpd via
     80 * "opt OPTION_NAME OPTION_VALUE" directives in udhcpd.conf file.
     81 */
     82/* Must match dhcp_optflags[] order */
     83const char dhcp_option_strings[] ALIGN1 =
     84    "subnet" "\0"      /* DHCP_SUBNET         */
     85    "timezone" "\0"    /* DHCP_TIME_OFFSET    */
     86    "router" "\0"      /* DHCP_ROUTER         */
     87//  "timesrv" "\0"     /* DHCP_TIME_SERVER    */
     88//  "namesrv" "\0"     /* DHCP_NAME_SERVER    */
     89    "dns" "\0"         /* DHCP_DNS_SERVER     */
     90//  "logsrv" "\0"      /* DHCP_LOG_SERVER     */
     91//  "cookiesrv" "\0"   /* DHCP_COOKIE_SERVER  */
     92    "lprsrv" "\0"      /* DHCP_LPR_SERVER     */
     93    "hostname" "\0"    /* DHCP_HOST_NAME      */
     94    "bootsize" "\0"    /* DHCP_BOOT_SIZE      */
     95    "domain" "\0"      /* DHCP_DOMAIN_NAME    */
     96    "swapsrv" "\0"     /* DHCP_SWAP_SERVER    */
     97    "rootpath" "\0"    /* DHCP_ROOT_PATH      */
     98    "ipttl" "\0"       /* DHCP_IP_TTL         */
     99    "mtu" "\0"         /* DHCP_MTU            */
     100    "broadcast" "\0"   /* DHCP_BROADCAST      */
     101    "routes" "\0"      /* DHCP_ROUTES         */
     102    "nisdomain" "\0"   /* DHCP_NIS_DOMAIN     */
     103    "nissrv" "\0"      /* DHCP_NIS_SERVER     */
     104    "ntpsrv" "\0"      /* DHCP_NTP_SERVER     */
     105    "wins" "\0"        /* DHCP_WINS_SERVER    */
     106    "lease" "\0"       /* DHCP_LEASE_TIME     */
     107    "serverid" "\0"    /* DHCP_SERVER_ID      */
     108    "message" "\0"     /* DHCP_ERR_MESSAGE    */
     109    "tftp" "\0"        /* DHCP_TFTP_SERVER_NAME */
     110    "bootfile" "\0"    /* DHCP_BOOT_FILE      */
     111//  "userclass" "\0"   /* DHCP_USER_CLASS     */
     112#if ENABLE_FEATURE_UDHCP_RFC3397
     113    "search" "\0"      /* DHCP_DOMAIN_SEARCH  */
     114// doesn't work in udhcpd.conf since OPTION_SIP_SERVERS
     115// is not handled yet by "string->option" conversion code:
     116    "sipsrv" "\0"      /* DHCP_SIP_SERVERS    */
     117#endif
     118// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES
     119// is not handled yet by "string->option" conversion code:
     120    "staticroutes" "\0"/* DHCP_STATIC_ROUTES  */
     121    "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */
     122    "wpad" "\0"        /* DHCP_WPAD           */
     123    ;
     124
     125/* Lengths of the option types in binary form.
     126 * Used by:
     127 * udhcp_str2optset: to determine how many bytes to allocate.
     128 * xmalloc_optname_optval: to estimate string length
     129 * from binary option length: (option[LEN] / dhcp_option_lengths[opt_type])
     130 * is the number of elements, multiply in by one element's string width
     131 * (len_of_option_as_string[opt_type]) and you know how wide string you need.
     132 */
     133const uint8_t dhcp_option_lengths[] ALIGN1 = {
     134    [OPTION_IP] =      4,
     135    [OPTION_IP_PAIR] = 8,
     136//  [OPTION_BOOLEAN] = 1,
     137    [OPTION_STRING] =  1,  /* ignored by udhcp_str2optset */
     138#if ENABLE_FEATURE_UDHCP_RFC3397
     139    [OPTION_DNS_STRING] = 1,  /* ignored by both udhcp_str2optset and xmalloc_optname_optval */
     140    [OPTION_SIP_SERVERS] = 1,
     141#endif
     142    [OPTION_U8] =      1,
     143    [OPTION_U16] =     2,
     144//  [OPTION_S16] =     2,
     145    [OPTION_U32] =     4,
     146    [OPTION_S32] =     4,
     147    /* Just like OPTION_STRING, we use minimum length here */
     148    [OPTION_STATIC_ROUTES] = 5,
     149};
     150
     151
     152#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
     153static void log_option(const char *pfx, const uint8_t *opt)
     154{
     155    if (dhcp_verbose >= 2) {
     156        char buf[256 * 2 + 2];
     157        *bin2hex(buf, (void*) (opt + OPT_DATA), opt[OPT_LEN]) = '\0';
     158        bb_info_msg("%s: 0x%02x %s", pfx, opt[OPT_CODE], buf);
     159    }
     160}
     161#else
     162# define log_option(pfx, opt) ((void)0)
     163#endif
     164
     165unsigned FAST_FUNC udhcp_option_idx(const char *name)
     166{
     167    int n = index_in_strings(dhcp_option_strings, name);
     168    if (n >= 0)
     169        return n;
     170
     171    {
     172        char buf[sizeof(dhcp_option_strings)];
     173        char *d = buf;
     174        const char *s = dhcp_option_strings;
     175        while (s < dhcp_option_strings + sizeof(dhcp_option_strings) - 2) {
     176            *d++ = (*s == '\0' ? ' ' : *s);
     177            s++;
     178        }
     179        *d = '\0';
     180        bb_error_msg_and_die("unknown option '%s', known options: %s", name, buf);
     181    }
     182}
     183
     184/* Get an option with bounds checking (warning, result is not aligned) */
     185uint8_t* FAST_FUNC udhcp_get_option(struct dhcp_packet *packet, int code)
     186{
     187    uint8_t *optionptr;
     188    int len;
     189    int rem;
     190    int overload = 0;
     191    enum {
     192        FILE_FIELD101  = FILE_FIELD  * 0x101,
     193        SNAME_FIELD101 = SNAME_FIELD * 0x101,
     194    };
     195
     196    /* option bytes: [code][len][data1][data2]..[dataLEN] */
     197    optionptr = packet->options;
     198    rem = sizeof(packet->options);
     199    while (1) {
     200        if (rem <= 0) {
     201            bb_error_msg("bad packet, malformed option field");
     202            return NULL;
     203        }
     204        if (optionptr[OPT_CODE] == DHCP_PADDING) {
     205            rem--;
     206            optionptr++;
     207            continue;
     208        }
     209        if (optionptr[OPT_CODE] == DHCP_END) {
     210            if ((overload & FILE_FIELD101) == FILE_FIELD) {
     211                /* can use packet->file, and didn't look at it yet */
     212                overload |= FILE_FIELD101; /* "we looked at it" */
     213                optionptr = packet->file;
     214                rem = sizeof(packet->file);
     215                continue;
     216            }
     217            if ((overload & SNAME_FIELD101) == SNAME_FIELD) {
     218                /* can use packet->sname, and didn't look at it yet */
     219                overload |= SNAME_FIELD101; /* "we looked at it" */
     220                optionptr = packet->sname;
     221                rem = sizeof(packet->sname);
     222                continue;
     223            }
     224            break;
     225        }
     226        len = 2 + optionptr[OPT_LEN];
     227        rem -= len;
     228        if (rem < 0)
     229            continue; /* complain and return NULL */
     230
     231        if (optionptr[OPT_CODE] == code) {
     232            log_option("Option found", optionptr);
     233            return optionptr + OPT_DATA;
     234        }
     235
     236        if (optionptr[OPT_CODE] == DHCP_OPTION_OVERLOAD) {
     237            overload |= optionptr[OPT_DATA];
     238            /* fall through */
     239        }
     240        optionptr += len;
     241    }
     242
     243    /* log3 because udhcpc uses it a lot - very noisy */
     244    log3("Option 0x%02x not found", code);
     245    return NULL;
     246}
     247
     248/* Return the position of the 'end' option (no bounds checking) */
     249int FAST_FUNC udhcp_end_option(uint8_t *optionptr)
     250{
     251    int i = 0;
     252
     253    while (optionptr[i] != DHCP_END) {
     254        if (optionptr[i] != DHCP_PADDING)
     255            i += optionptr[i + OPT_LEN] + OPT_DATA-1;
     256        i++;
     257    }
     258    return i;
     259}
     260
     261/* Add an option (supplied in binary form) to the options.
     262 * Option format: [code][len][data1][data2]..[dataLEN]
     263 */
     264void FAST_FUNC udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt)
     265{
     266    unsigned len;
     267    uint8_t *optionptr = packet->options;
     268    unsigned end = udhcp_end_option(optionptr);
     269
     270    len = OPT_DATA + addopt[OPT_LEN];
     271    /* end position + (option code/length + addopt length) + end option */
     272    if (end + len + 1 >= DHCP_OPTIONS_BUFSIZE) {
     273//TODO: learn how to use overflow option if we exhaust packet->options[]
     274        bb_error_msg("option 0x%02x did not fit into the packet",
     275                addopt[OPT_CODE]);
     276        return;
     277    }
     278    log_option("Adding option", addopt);
     279    memcpy(optionptr + end, addopt, len);
     280    optionptr[end + len] = DHCP_END;
     281}
     282
     283/* Add an one to four byte option to a packet */
     284void FAST_FUNC udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data)
     285{
     286    const struct dhcp_optflag *dh;
     287
     288    for (dh = dhcp_optflags; dh->code; dh++) {
     289        if (dh->code == code) {
     290            uint8_t option[6], len;
     291
     292            option[OPT_CODE] = code;
     293            len = dhcp_option_lengths[dh->flags & OPTION_TYPE_MASK];
     294            option[OPT_LEN] = len;
     295            if (BB_BIG_ENDIAN)
     296                data <<= 8 * (4 - len);
     297            /* Assignment is unaligned! */
     298            move_to_unaligned32(&option[OPT_DATA], data);
     299            udhcp_add_binary_option(packet, option);
     300            return;
     301        }
     302    }
     303
     304    bb_error_msg("can't add option 0x%02x", code);
     305}
     306
     307/* Find option 'code' in opt_list */
     308struct option_set* FAST_FUNC udhcp_find_option(struct option_set *opt_list, uint8_t code)
     309{
     310    while (opt_list && opt_list->data[OPT_CODE] < code)
     311        opt_list = opt_list->next;
     312
     313    if (opt_list && opt_list->data[OPT_CODE] == code)
     314        return opt_list;
     315    return NULL;
     316}
     317
     318/* Parse string to IP in network order */
     319int FAST_FUNC udhcp_str2nip(const char *str, void *arg)
     320{
     321    len_and_sockaddr *lsa;
     322
     323    lsa = host_and_af2sockaddr(str, 0, AF_INET);
     324    if (!lsa)
     325        return 0;
     326    *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr;
     327    free(lsa);
     328    return 1;
     329}
     330
     331/* udhcp_str2optset:
     332 * Parse string option representation to binary form and add it to opt_list.
     333 * Called to parse "udhcpc -x OPTNAME:OPTVAL"
     334 * and to parse udhcpd.conf's "opt OPTNAME OPTVAL" directives.
     335 */
     336/* helper for the helper */
     337static char *allocate_tempopt_if_needed(
     338        const struct dhcp_optflag *optflag,
     339        char *buffer,
     340        int *length_p)
     341{
     342    char *allocated = NULL;
     343    if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_BIN) {
     344        const char *end;
     345        allocated = xstrdup(buffer); /* more than enough */
     346        end = hex2bin(allocated, buffer, 255);
     347        if (errno)
     348            bb_error_msg_and_die("malformed hex string '%s'", buffer);
     349        *length_p = end - allocated;
     350    }
     351    return allocated;
     352}
     353/* helper: add an option to the opt_list */
     354static NOINLINE void attach_option(
     355        struct option_set **opt_list,
     356        const struct dhcp_optflag *optflag,
     357        char *buffer,
     358        int length)
     359{
     360    struct option_set *existing, *new, **curr;
     361    char *allocated = NULL;
     362
     363    existing = udhcp_find_option(*opt_list, optflag->code);
     364    if (!existing) {
     365        log2("Attaching option %02x to list", optflag->code);
     366        allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
     367#if ENABLE_FEATURE_UDHCP_RFC3397
     368        if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
     369            /* reuse buffer and length for RFC1035-formatted string */
     370            allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length);
     371        }
     372#endif
     373        /* make a new option */
     374        new = xmalloc(sizeof(*new));
     375        new->data = xmalloc(length + OPT_DATA);
     376        new->data[OPT_CODE] = optflag->code;
     377        new->data[OPT_LEN] = length;
     378        memcpy(new->data + OPT_DATA, (allocated ? allocated : buffer), length);
     379
     380        curr = opt_list;
     381        while (*curr && (*curr)->data[OPT_CODE] < optflag->code)
     382            curr = &(*curr)->next;
     383
     384        new->next = *curr;
     385        *curr = new;
     386        goto ret;
     387    }
     388
     389    if (optflag->flags & OPTION_LIST) {
     390        unsigned old_len;
     391
     392        /* add it to an existing option */
     393        log2("Attaching option %02x to existing member of list", optflag->code);
     394        allocated = allocate_tempopt_if_needed(optflag, buffer, &length);
     395        old_len = existing->data[OPT_LEN];
     396#if ENABLE_FEATURE_UDHCP_RFC3397
     397        if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) {
     398            /* reuse buffer and length for RFC1035-formatted string */
     399            allocated = buffer = (char *)dname_enc(existing->data + OPT_DATA, old_len, buffer, &length);
     400        }
     401#endif
     402        if (old_len + length < 255) {
     403            /* actually 255 is ok too, but adding a space can overlow it */
     404
     405            existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length);
     406            if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING) {
     407                /* add space separator between STRING options in a list */
     408                existing->data[OPT_DATA + old_len] = ' ';
     409                old_len++;
     410            }
     411            memcpy(existing->data + OPT_DATA + old_len, buffer, length);
     412            existing->data[OPT_LEN] = old_len + length;
     413        } /* else, ignore the data, we could put this in a second option in the future */
     414    } /* else, ignore the new data */
     415
     416 ret:
     417    free(allocated);
     418}
     419
     420int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg)
     421{
     422    struct option_set **opt_list = arg;
     423    char *opt, *val, *endptr;
     424    char *str;
     425    const struct dhcp_optflag *optflag;
     426    struct dhcp_optflag bin_optflag;
     427    unsigned optcode;
     428    int retval, length;
     429    char buffer[8] ALIGNED(4);
     430    uint16_t *result_u16 = (uint16_t *) buffer;
     431    uint32_t *result_u32 = (uint32_t *) buffer;
     432
     433    /* Cheat, the only *const* str possible is "" */
     434    str = (char *) const_str;
     435    opt = strtok(str, " \t=");
     436    if (!opt)
     437        return 0;
     438
     439    optcode = bb_strtou(opt, NULL, 0);
     440    if (!errno && optcode < 255) {
     441        /* Raw (numeric) option code */
     442        bin_optflag.flags = OPTION_BIN;
     443        bin_optflag.code = optcode;
     444        optflag = &bin_optflag;
     445    } else {
     446        optflag = &dhcp_optflags[udhcp_option_idx(opt)];
     447    }
     448
     449    retval = 0;
     450    do {
     451        val = strtok(NULL, ", \t");
     452        if (!val)
     453            break;
     454        length = dhcp_option_lengths[optflag->flags & OPTION_TYPE_MASK];
     455        retval = 0;
     456        opt = buffer; /* new meaning for variable opt */
     457        switch (optflag->flags & OPTION_TYPE_MASK) {
     458        case OPTION_IP:
     459            retval = udhcp_str2nip(val, buffer);
     460            break;
     461        case OPTION_IP_PAIR:
     462            retval = udhcp_str2nip(val, buffer);
     463            val = strtok(NULL, ", \t/-");
     464            if (!val)
     465                retval = 0;
     466            if (retval)
     467                retval = udhcp_str2nip(val, buffer + 4);
     468            break;
     469        case OPTION_STRING:
     470#if ENABLE_FEATURE_UDHCP_RFC3397
     471        case OPTION_DNS_STRING:
     472#endif
     473            length = strnlen(val, 254);
     474            if (length > 0) {
     475                opt = val;
     476                retval = 1;
     477            }
     478            break;
     479//      case OPTION_BOOLEAN: {
     480//          static const char no_yes[] ALIGN1 = "no\0yes\0";
     481//          buffer[0] = retval = index_in_strings(no_yes, val);
     482//          retval++; /* 0 - bad; 1: "no" 2: "yes" */
     483//          break;
     484//      }
     485        case OPTION_U8:
     486            buffer[0] = strtoul(val, &endptr, 0);
     487            retval = (endptr[0] == '\0');
     488            break;
     489        /* htonX are macros in older libc's, using temp var
     490         * in code below for safety */
     491        /* TODO: use bb_strtoX? */
     492        case OPTION_U16: {
     493            unsigned long tmp = strtoul(val, &endptr, 0);
     494            *result_u16 = htons(tmp);
     495            retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/);
     496            break;
     497        }
     498//      case OPTION_S16: {
     499//          long tmp = strtol(val, &endptr, 0);
     500//          *result_u16 = htons(tmp);
     501//          retval = (endptr[0] == '\0');
     502//          break;
     503//      }
     504        case OPTION_U32: {
     505            unsigned long tmp = strtoul(val, &endptr, 0);
     506            *result_u32 = htonl(tmp);
     507            retval = (endptr[0] == '\0');
     508            break;
     509        }
     510        case OPTION_S32: {
     511            long tmp = strtol(val, &endptr, 0);
     512            *result_u32 = htonl(tmp);
     513            retval = (endptr[0] == '\0');
     514            break;
     515        }
     516        case OPTION_BIN: /* handled in attach_option() */
     517            opt = val;
     518            retval = 1;
     519        default:
     520            break;
     521        }
     522        if (retval)
     523            attach_option(opt_list, optflag, opt, length);
     524    } while (retval && optflag->flags & OPTION_LIST);
     525
     526    return retval;
     527}
  • branches/2.2.9/mindi-busybox/networking/udhcp/common.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* common.h
    3  *
     2/*
    43 * Russ Dill <Russ.Dill@asu.edu> September 2001
    54 * Rewritten by Vladimir Oleynik <dzo@simtreas.ru> (C) 2003
    65 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    87 */
    9 
    10 #ifndef _COMMON_H
    11 #define _COMMON_H
     8#ifndef UDHCP_COMMON_H
     9#define UDHCP_COMMON_H 1
    1210
    1311#include "libbb.h"
    14 
    15 #define DEFAULT_SCRIPT  "/usr/share/udhcpc/default.script"
    16 
    17 extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */
    18 
    19 /*** packet.h ***/
    20 
    2112#include <netinet/udp.h>
    2213#include <netinet/ip.h>
    2314
    24 struct dhcpMessage {
    25     uint8_t op;
    26     uint8_t htype;
    27     uint8_t hlen;
    28     uint8_t hops;
    29     uint32_t xid;
    30     uint16_t secs;
    31     uint16_t flags;
    32     uint32_t ciaddr;
    33     uint32_t yiaddr;
    34     uint32_t siaddr;
    35     uint32_t giaddr;
    36     uint8_t chaddr[16];
    37     uint8_t sname[64];
    38     uint8_t file[128];
    39     uint32_t cookie;
    40     uint8_t options[308]; /* 312 - cookie */
    41 };
    42 
    43 struct udp_dhcp_packet {
     15PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
     16
     17extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */
     18
     19
     20/*** DHCP packet ***/
     21
     22/* DHCP protocol. See RFC 2131 */
     23#define DHCP_MAGIC              0x63825363
     24#define DHCP_OPTIONS_BUFSIZE    308
     25#define BOOTREQUEST             1
     26#define BOOTREPLY               2
     27
     28//TODO: rename ciaddr/yiaddr/chaddr
     29struct dhcp_packet {
     30    uint8_t op;      /* BOOTREQUEST or BOOTREPLY */
     31    uint8_t htype;   /* hardware address type. 1 = 10mb ethernet */
     32    uint8_t hlen;    /* hardware address length */
     33    uint8_t hops;    /* used by relay agents only */
     34    uint32_t xid;    /* unique id */
     35    uint16_t secs;   /* elapsed since client began acquisition/renewal */
     36    uint16_t flags;  /* only one flag so far: */
     37#define BROADCAST_FLAG 0x8000 /* "I need broadcast replies" */
     38    uint32_t ciaddr; /* client IP (if client is in BOUND, RENEW or REBINDING state) */
     39    uint32_t yiaddr; /* 'your' (client) IP address */
     40    /* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */
     41    uint32_t siaddr_nip;
     42    uint32_t gateway_nip; /* relay agent IP address */
     43    uint8_t chaddr[16];   /* link-layer client hardware address (MAC) */
     44    uint8_t sname[64];    /* server host name (ASCIZ) */
     45    uint8_t file[128];    /* boot file name (ASCIZ) */
     46    uint32_t cookie;      /* fixed first four option bytes (99,130,83,99 dec) */
     47    uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS];
     48} PACKED;
     49#define DHCP_PKT_SNAME_LEN      64
     50#define DHCP_PKT_FILE_LEN      128
     51#define DHCP_PKT_SNAME_LEN_STR "64"
     52#define DHCP_PKT_FILE_LEN_STR "128"
     53
     54struct ip_udp_dhcp_packet {
    4455    struct iphdr ip;
    4556    struct udphdr udp;
    46     struct dhcpMessage data;
    47 };
    48 
    49 void udhcp_init_header(struct dhcpMessage *packet, char type);
    50 int udhcp_get_packet(struct dhcpMessage *packet, int fd);
    51 uint16_t udhcp_checksum(void *addr, int count);
    52 int udhcp_raw_packet(struct dhcpMessage *payload,
    53         uint32_t source_ip, int source_port,
    54         uint32_t dest_ip, int dest_port,
    55         const uint8_t *dest_arp, int ifindex);
    56 int udhcp_kernel_packet(struct dhcpMessage *payload,
    57         uint32_t source_ip, int source_port,
    58         uint32_t dest_ip, int dest_port);
    59 
    60 
    61 /**/
    62 
    63 void udhcp_run_script(struct dhcpMessage *packet, const char *name);
    64 
    65 // Still need to clean these up...
    66 
    67 /* from options.h */
    68 #define get_option      udhcp_get_option
    69 #define end_option      udhcp_end_option
    70 #define add_option_string   udhcp_add_option_string
    71 #define add_simple_option   udhcp_add_simple_option
    72 #define option_lengths      udhcp_option_lengths
    73 /* from socket.h */
    74 #define listen_socket       udhcp_listen_socket
    75 #define read_interface      udhcp_read_interface
    76 /* from dhcpc.h */
    77 #define client_config       udhcp_client_config
    78 /* from dhcpd.h */
    79 #define server_config       udhcp_server_config
    80 
    81 void udhcp_sp_setup(void);
    82 int udhcp_sp_fd_set(fd_set *rfds, int extra_fd);
    83 int udhcp_sp_read(fd_set *rfds);
    84 int raw_socket(int ifindex);
    85 int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp);
    86 int listen_socket(/*uint32_t ip,*/ int port, const char *inf);
     57    struct dhcp_packet data;
     58} PACKED;
     59
     60struct udp_dhcp_packet {
     61    struct udphdr udp;
     62    struct dhcp_packet data;
     63} PACKED;
     64
     65enum {
     66    IP_UDP_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
     67    UDP_DHCP_SIZE    = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
     68    DHCP_SIZE        = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
     69};
     70
     71/* Let's see whether compiler understood us right */
     72struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet {
     73    char c[IP_UDP_DHCP_SIZE == 576 ? 1 : -1];
     74};
     75
     76
     77/*** Options ***/
     78
     79enum {
     80    OPTION_IP = 1,
     81    OPTION_IP_PAIR,
     82    OPTION_STRING,
     83//  OPTION_BOOLEAN,
     84    OPTION_U8,
     85    OPTION_U16,
     86//  OPTION_S16,
     87    OPTION_U32,
     88    OPTION_S32,
     89    OPTION_BIN,
     90    OPTION_STATIC_ROUTES,
     91#if ENABLE_FEATURE_UDHCP_RFC3397
     92    OPTION_DNS_STRING,  /* RFC1035 compressed domain name list */
     93    OPTION_SIP_SERVERS,
     94#endif
     95
     96    OPTION_TYPE_MASK = 0x0f,
     97    /* Client requests this option by default */
     98    OPTION_REQ  = 0x10,
     99    /* There can be a list of 1 or more of these */
     100    OPTION_LIST = 0x20,
     101};
     102
     103/* DHCP option codes (partial list). See RFC 2132 and
     104 * http://www.iana.org/assignments/bootp-dhcp-parameters/
     105 * Commented out options are handled by common option machinery,
     106 * uncommented ones have spacial cases (grep for them to see).
     107 */
     108#define DHCP_PADDING            0x00
     109#define DHCP_SUBNET             0x01
     110//#define DHCP_TIME_OFFSET      0x02 /* (localtime - UTC_time) in seconds. signed */
     111//#define DHCP_ROUTER           0x03
     112//#define DHCP_TIME_SERVER      0x04 /* RFC 868 time server (32-bit, 0 = 1.1.1900) */
     113//#define DHCP_NAME_SERVER      0x05 /* IEN 116 _really_ ancient kind of NS */
     114//#define DHCP_DNS_SERVER       0x06
     115//#define DHCP_LOG_SERVER       0x07 /* port 704 UDP log (not syslog)
     116//#define DHCP_COOKIE_SERVER    0x08 /* "quote of the day" server */
     117//#define DHCP_LPR_SERVER       0x09
     118#define DHCP_HOST_NAME          0x0c /* either client informs server or server gives name to client */
     119//#define DHCP_BOOT_SIZE        0x0d
     120//#define DHCP_DOMAIN_NAME      0x0f /* server gives domain suffix */
     121//#define DHCP_SWAP_SERVER      0x10
     122//#define DHCP_ROOT_PATH        0x11
     123//#define DHCP_IP_TTL           0x17
     124//#define DHCP_MTU              0x1a
     125//#define DHCP_BROADCAST        0x1c
     126//#define DHCP_ROUTES           0x21
     127//#define DHCP_NIS_DOMAIN       0x28
     128//#define DHCP_NIS_SERVER       0x29
     129//#define DHCP_NTP_SERVER       0x2a
     130//#define DHCP_WINS_SERVER      0x2c
     131#define DHCP_REQUESTED_IP       0x32 /* sent by client if specific IP is wanted */
     132#define DHCP_LEASE_TIME         0x33
     133#define DHCP_OPTION_OVERLOAD    0x34
     134#define DHCP_MESSAGE_TYPE       0x35
     135#define DHCP_SERVER_ID          0x36 /* by default server's IP */
     136#define DHCP_PARAM_REQ          0x37 /* list of options client wants */
     137//#define DHCP_ERR_MESSAGE      0x38 /* error message when sending NAK etc */
     138#define DHCP_MAX_SIZE           0x39
     139#define DHCP_VENDOR             0x3c /* client's vendor (a string) */
     140#define DHCP_CLIENT_ID          0x3d /* by default client's MAC addr, but may be arbitrarily long */
     141//#define DHCP_TFTP_SERVER_NAME 0x42 /* same as 'sname' field */
     142//#define DHCP_BOOT_FILE        0x43 /* same as 'file' field */
     143//#define DHCP_USER_CLASS       0x4d /* RFC 3004. set of LASCII strings. "I am a printer" etc */
     144#define DHCP_FQDN               0x51 /* client asks to update DNS to map its FQDN to its new IP */
     145//#define DHCP_DOMAIN_SEARCH    0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */
     146//#define DHCP_SIP_SERVERS      0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */
     147//#define DHCP_STATIC_ROUTES    0x79 /* RFC 3442. (mask,ip,router) tuples */
     148//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */
     149//#define DHCP_WPAD             0xfc /* MSIE's Web Proxy Autodiscovery Protocol */
     150#define DHCP_END                0xff
     151
     152/* Offsets in option byte sequence */
     153#define OPT_CODE                0
     154#define OPT_LEN                 1
     155#define OPT_DATA                2
     156/* Bits in "overload" option */
     157#define OPTION_FIELD            0
     158#define FILE_FIELD              1
     159#define SNAME_FIELD             2
     160
     161/* DHCP_MESSAGE_TYPE values */
     162#define DHCPDISCOVER            1 /* client -> server */
     163#define DHCPOFFER               2 /* client <- server */
     164#define DHCPREQUEST             3 /* client -> server */
     165#define DHCPDECLINE             4 /* client -> server */
     166#define DHCPACK                 5 /* client <- server */
     167#define DHCPNAK                 6 /* client <- server */
     168#define DHCPRELEASE             7 /* client -> server */
     169#define DHCPINFORM              8 /* client -> server */
     170#define DHCP_MINTYPE DHCPDISCOVER
     171#define DHCP_MAXTYPE DHCPINFORM
     172
     173struct dhcp_optflag {
     174    uint8_t flags;
     175    uint8_t code;
     176};
     177
     178struct option_set {
     179    uint8_t *data;
     180    struct option_set *next;
     181};
     182
     183extern const struct dhcp_optflag dhcp_optflags[];
     184extern const char dhcp_option_strings[];
     185extern const uint8_t dhcp_option_lengths[];
     186
     187unsigned FAST_FUNC udhcp_option_idx(const char *name);
     188
     189uint8_t *udhcp_get_option(struct dhcp_packet *packet, int code) FAST_FUNC;
     190int udhcp_end_option(uint8_t *optionptr) FAST_FUNC;
     191void udhcp_add_binary_option(struct dhcp_packet *packet, uint8_t *addopt) FAST_FUNC;
     192void udhcp_add_simple_option(struct dhcp_packet *packet, uint8_t code, uint32_t data) FAST_FUNC;
     193#if ENABLE_FEATURE_UDHCP_RFC3397
     194char *dname_dec(const uint8_t *cstr, int clen, const char *pre) FAST_FUNC;
     195uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen) FAST_FUNC;
     196#endif
     197struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC;
     198
     199
     200// RFC 2131  Table 5: Fields and options used by DHCP clients
     201//
     202// Fields 'hops', 'yiaddr', 'siaddr', 'giaddr' are always zero
     203//
     204// Field      DHCPDISCOVER          DHCPINFORM            DHCPREQUEST           DHCPDECLINE         DHCPRELEASE
     205// -----      ------------          ------------          -----------           -----------         -----------
     206// 'xid'      selected by client    selected by client    'xid' from server     selected by client  selected by client
     207//                                                        DHCPOFFER message
     208// 'secs'     0 or seconds since    0 or seconds since    0 or seconds since    0                   0
     209//            DHCP process started  DHCP process started  DHCP process started
     210// 'flags'    Set 'BROADCAST'       Set 'BROADCAST'       Set 'BROADCAST'       0                   0
     211//            flag if client        flag if client        flag if client
     212//            requires broadcast    requires broadcast    requires broadcast
     213//            reply                 reply                 reply
     214// 'ciaddr'   0                     client's IP           0 or client's IP      0                   client's IP
     215//                                                        (BOUND/RENEW/REBIND)
     216// 'chaddr'   client's MAC          client's MAC          client's MAC          client's MAC        client's MAC
     217// 'sname'    options or sname      options or sname      options or sname      (unused)            (unused)
     218// 'file'     options or file       options or file       options or file       (unused)            (unused)
     219// 'options'  options               options               options               message type opt    message type opt
     220//
     221// Option                     DHCPDISCOVER  DHCPINFORM  DHCPREQUEST      DHCPDECLINE  DHCPRELEASE
     222// ------                     ------------  ----------  -----------      -----------  -----------
     223// Requested IP address       MAY           MUST NOT    MUST (in         MUST         MUST NOT
     224//                                                      SELECTING or
     225//                                                      INIT-REBOOT)
     226//                                                      MUST NOT (in
     227//                                                      BOUND or
     228//                                                      RENEWING)
     229// IP address lease time      MAY           MUST NOT    MAY              MUST NOT     MUST NOT
     230// Use 'file'/'sname' fields  MAY           MAY         MAY              MAY          MAY
     231// Client identifier          MAY           MAY         MAY              MAY          MAY
     232// Vendor class identifier    MAY           MAY         MAY              MUST NOT     MUST NOT
     233// Server identifier          MUST NOT      MUST NOT    MUST (after      MUST         MUST
     234//                                                      SELECTING)
     235//                                                      MUST NOT (after
     236//                                                      INIT-REBOOT,
     237//                                                      BOUND, RENEWING
     238//                                                      or REBINDING)
     239// Parameter request list     MAY           MAY         MAY              MUST NOT     MUST NOT
     240// Maximum message size       MAY           MAY         MAY              MUST NOT     MUST NOT
     241// Message                    SHOULD NOT    SHOULD NOT  SHOULD NOT       SHOULD       SHOULD
     242// Site-specific              MAY           MAY         MAY              MUST NOT     MUST NOT
     243// All others                 MAY           MAY         MAY              MUST NOT     MUST NOT
     244
     245
     246/*** Logging ***/
     247
     248#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     249extern unsigned dhcp_verbose;
     250# define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0)
     251# if CONFIG_UDHCP_DEBUG >= 2
     252void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC;
     253#  define log2(...) do { if (dhcp_verbose >= 2) bb_info_msg(__VA_ARGS__); } while (0)
     254# else
     255#  define udhcp_dump_packet(...) ((void)0)
     256#  define log2(...) ((void)0)
     257# endif
     258# if CONFIG_UDHCP_DEBUG >= 3
     259#  define log3(...) do { if (dhcp_verbose >= 3) bb_info_msg(__VA_ARGS__); } while (0)
     260# else
     261#  define log3(...) ((void)0)
     262# endif
     263#else
     264# define udhcp_dump_packet(...) ((void)0)
     265# define log1(...) ((void)0)
     266# define log2(...) ((void)0)
     267# define log3(...) ((void)0)
     268#endif
     269
     270
     271/*** Other shared functions ***/
     272
     273/* 2nd param is "uint32_t*" */
     274int FAST_FUNC udhcp_str2nip(const char *str, void *arg);
     275/* 2nd param is "struct option_set**" */
     276int FAST_FUNC udhcp_str2optset(const char *str, void *arg);
     277
     278uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC;
     279
     280void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC;
     281
     282int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC;
     283
     284int udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
     285        uint32_t source_nip, int source_port,
     286        uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
     287        int ifindex) FAST_FUNC;
     288
     289int udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
     290        uint32_t source_nip, int source_port,
     291        uint32_t dest_nip, int dest_port) FAST_FUNC;
     292
     293void udhcp_sp_setup(void) FAST_FUNC;
     294int udhcp_sp_fd_set(fd_set *rfds, int extra_fd) FAST_FUNC;
     295int udhcp_sp_read(const fd_set *rfds) FAST_FUNC;
     296
     297int udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) FAST_FUNC;
     298
     299int udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) FAST_FUNC;
     300
    87301/* Returns 1 if no reply received */
    88 int arpping(uint32_t test_ip, uint32_t from_ip, uint8_t *from_mac, const char *interface);
    89 
    90 #if ENABLE_FEATURE_UDHCP_DEBUG
    91 # define DEBUG(str, args...) bb_info_msg(str, ## args)
    92 #else
    93 # define DEBUG(str, args...) do {;} while (0)
     302int arpping(uint32_t test_nip,
     303        const uint8_t *safe_mac,
     304        uint32_t from_ip,
     305        uint8_t *from_mac,
     306        const char *interface) FAST_FUNC;
     307
     308POP_SAVED_FUNCTION_VISIBILITY
     309
    94310#endif
    95 
    96 #endif
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcpc.c

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

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* dhcpc.h */
    3 #ifndef _DHCPC_H
    4 #define _DHCPC_H
     2/*
     3 * Licensed under GPLv2, see file LICENSE in this source tree.
     4 */
     5#ifndef UDHCP_DHCPC_H
     6#define UDHCP_DHCPC_H 1
    57
    6 #define INIT_SELECTING  0
    7 #define REQUESTING  1
    8 #define BOUND       2
    9 #define RENEWING    3
    10 #define REBINDING   4
    11 #define INIT_REBOOT 5
    12 #define RENEW_REQUESTED 6
    13 #define RELEASED    7
     8PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
    149
    1510struct client_config_t {
    16     /* TODO: combine flag fields into single "unsigned opt" */
    17     /* (can be set directly to the result of getopt32) */
    18     char foreground;                /* Do not fork */
    19     char quit_after_lease;          /* Quit after obtaining lease */
    20     char release_on_quit;           /* Perform release on quit */
    21     char abort_if_no_lease;         /* Abort if no lease */
    22     char background_if_no_lease;    /* Fork to background if no lease */
     11    uint8_t client_mac[6];          /* Our mac address */
     12    char no_default_options;        /* Do not include default options in request */
     13    IF_FEATURE_UDHCP_PORT(uint16_t port;)
     14    int ifindex;                    /* Index number of the interface to use */
     15    uint8_t opt_mask[256 / 8];      /* Bitmask of options to send (-O option) */
    2316    const char *interface;          /* The name of the interface to use */
    2417    char *pidfile;                  /* Optionally store the process ID */
    2518    const char *script;             /* User script to run at dhcp events */
     19    struct option_set *options;     /* list of DHCP options to send to server */
    2620    uint8_t *clientid;              /* Optional client id to use */
    2721    uint8_t *vendorclass;           /* Optional vendor class-id to use */
    2822    uint8_t *hostname;              /* Optional hostname to use */
    2923    uint8_t *fqdn;                  /* Optional fully qualified domain name to use */
    30     int ifindex;                    /* Index number of the interface to use */
    31     int retries;                    /* Max number of request packets */
    32     int timeout;                    /* Number of seconds to try to get a lease */
    33     uint8_t arp[6];                 /* Our arp address */
    34 };
     24} FIX_ALIASING;
    3525
    36 extern struct client_config_t client_config;
     26/* server_config sits in 1st half of bb_common_bufsiz1 */
     27#define client_config (*(struct client_config_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE / 2]))
    3728
     29#if ENABLE_FEATURE_UDHCP_PORT
     30#define CLIENT_PORT (client_config.port)
     31#else
     32#define CLIENT_PORT 68
     33#endif
    3834
    39 /*** clientpacket.h ***/
    40 
    41 uint32_t random_xid(void);
    42 int send_discover(uint32_t xid, uint32_t requested);
    43 int send_selecting(uint32_t xid, uint32_t server, uint32_t requested);
    44 int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr);
    45 int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr);
    46 int send_release(uint32_t server, uint32_t ciaddr);
    47 int get_raw_packet(struct dhcpMessage *payload, int fd);
    48 
     35POP_SAVED_FUNCTION_VISIBILITY
    4936
    5037#endif
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcpd.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* dhcpd.c
    3  *
    4  * udhcp Server
     2/*
     3 * udhcp server
    54 * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
    65 *          Chris Trew <ctrew@moreton.com.au>
     
    87 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
    98 *
    10  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     9 * This program is free software; you can redistribute it and/or modify
     10 * it under the terms of the GNU General Public License as published by
     11 * the Free Software Foundation; either version 2 of the License, or
     12 * (at your option) any later version.
     13 *
     14 * This program is distributed in the hope that it will be useful,
     15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 * GNU General Public License for more details.
     18 *
     19 * You should have received a copy of the GNU General Public License
     20 * along with this program; if not, write to the Free Software
     21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    1122 */
    12 
    1323#include <syslog.h>
    1424#include "common.h"
     25#include "dhcpc.h"
    1526#include "dhcpd.h"
    16 #include "options.h"
     27
     28
     29/* Send a packet to a specific mac address and ip address by creating our own ip packet */
     30static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast)
     31{
     32    const uint8_t *chaddr;
     33    uint32_t ciaddr;
     34
     35    // Was:
     36    //if (force_broadcast) { /* broadcast */ }
     37    //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
     38    //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
     39    //else { /* unicast to dhcp_pkt->yiaddr */ }
     40    // But this is wrong: yiaddr is _our_ idea what client's IP is
     41    // (for example, from lease file). Client may not know that,
     42    // and may not have UDP socket listening on that IP!
     43    // We should never unicast to dhcp_pkt->yiaddr!
     44    // dhcp_pkt->ciaddr, OTOH, comes from client's request packet,
     45    // and can be used.
     46
     47    if (force_broadcast
     48     || (dhcp_pkt->flags & htons(BROADCAST_FLAG))
     49     || dhcp_pkt->ciaddr == 0
     50    ) {
     51        log1("Broadcasting packet to client");
     52        ciaddr = INADDR_BROADCAST;
     53        chaddr = MAC_BCAST_ADDR;
     54    } else {
     55        log1("Unicasting packet to client ciaddr");
     56        ciaddr = dhcp_pkt->ciaddr;
     57        chaddr = dhcp_pkt->chaddr;
     58    }
     59
     60    udhcp_send_raw_packet(dhcp_pkt,
     61        /*src*/ server_config.server_nip, SERVER_PORT,
     62        /*dst*/ ciaddr, CLIENT_PORT, chaddr,
     63        server_config.ifindex);
     64}
     65
     66/* Send a packet to gateway_nip using the kernel ip stack */
     67static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
     68{
     69    log1("Forwarding packet to relay");
     70
     71    udhcp_send_kernel_packet(dhcp_pkt,
     72            server_config.server_nip, SERVER_PORT,
     73            dhcp_pkt->gateway_nip, SERVER_PORT);
     74}
     75
     76static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
     77{
     78    if (dhcp_pkt->gateway_nip)
     79        send_packet_to_relay(dhcp_pkt);
     80    else
     81        send_packet_to_client(dhcp_pkt, force_broadcast);
     82}
     83
     84static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
     85{
     86    /* Sets op, htype, hlen, cookie fields
     87     * and adds DHCP_MESSAGE_TYPE option */
     88    udhcp_init_header(packet, type);
     89
     90    packet->xid = oldpacket->xid;
     91    memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr));
     92    packet->flags = oldpacket->flags;
     93    packet->gateway_nip = oldpacket->gateway_nip;
     94    packet->ciaddr = oldpacket->ciaddr;
     95    udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_config.server_nip);
     96}
     97
     98/* Fill options field, siaddr_nip, and sname and boot_file fields.
     99 * TODO: teach this code to use overload option.
     100 */
     101static void add_server_options(struct dhcp_packet *packet)
     102{
     103    struct option_set *curr = server_config.options;
     104
     105    while (curr) {
     106        if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
     107            udhcp_add_binary_option(packet, curr->data);
     108        curr = curr->next;
     109    }
     110
     111    packet->siaddr_nip = server_config.siaddr_nip;
     112
     113    if (server_config.sname)
     114        strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1);
     115    if (server_config.boot_file)
     116        strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1);
     117}
     118
     119static uint32_t select_lease_time(struct dhcp_packet *packet)
     120{
     121    uint32_t lease_time_sec = server_config.max_lease_sec;
     122    uint8_t *lease_time_opt = udhcp_get_option(packet, DHCP_LEASE_TIME);
     123    if (lease_time_opt) {
     124        move_from_unaligned32(lease_time_sec, lease_time_opt);
     125        lease_time_sec = ntohl(lease_time_sec);
     126        if (lease_time_sec > server_config.max_lease_sec)
     127            lease_time_sec = server_config.max_lease_sec;
     128        if (lease_time_sec < server_config.min_lease_sec)
     129            lease_time_sec = server_config.min_lease_sec;
     130    }
     131    return lease_time_sec;
     132}
     133
     134/* We got a DHCP DISCOVER. Send an OFFER. */
     135/* NOINLINE: limit stack usage in caller */
     136static NOINLINE void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease)
     137{
     138    struct dhcp_packet packet;
     139    uint32_t lease_time_sec;
     140    struct in_addr addr;
     141
     142    init_packet(&packet, oldpacket, DHCPOFFER);
     143
     144    /* If it is a static lease, use its IP */
     145    packet.yiaddr = static_lease_nip;
     146    /* Else: */
     147    if (!static_lease_nip) {
     148        /* We have no static lease for client's chaddr */
     149        uint32_t req_nip;
     150        uint8_t *req_ip_opt;
     151        const char *p_host_name;
     152
     153        if (lease) {
     154            /* We have a dynamic lease for client's chaddr.
     155             * Reuse its IP (even if lease is expired).
     156             * Note that we ignore requested IP in this case.
     157             */
     158            packet.yiaddr = lease->lease_nip;
     159        }
     160        /* Or: if client has requested an IP */
     161        else if ((req_ip_opt = udhcp_get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL
     162         /* (read IP) */
     163         && (move_from_unaligned32(req_nip, req_ip_opt), 1)
     164         /* and the IP is in the lease range */
     165         && ntohl(req_nip) >= server_config.start_ip
     166         && ntohl(req_nip) <= server_config.end_ip
     167         /* and */
     168         && (  !(lease = find_lease_by_nip(req_nip)) /* is not already taken */
     169            || is_expired_lease(lease) /* or is taken, but expired */
     170            )
     171        ) {
     172            packet.yiaddr = req_nip;
     173        }
     174        else {
     175            /* Otherwise, find a free IP */
     176            packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr);
     177        }
     178
     179        if (!packet.yiaddr) {
     180            bb_error_msg("no free IP addresses. OFFER abandoned");
     181            return;
     182        }
     183        /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */
     184        p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
     185        lease = add_lease(packet.chaddr, packet.yiaddr,
     186                server_config.offer_time,
     187                p_host_name,
     188                p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
     189        );
     190        if (!lease) {
     191            bb_error_msg("no free IP addresses. OFFER abandoned");
     192            return;
     193        }
     194    }
     195
     196    lease_time_sec = select_lease_time(oldpacket);
     197    udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
     198    add_server_options(&packet);
     199
     200    addr.s_addr = packet.yiaddr;
     201    bb_info_msg("Sending OFFER of %s", inet_ntoa(addr));
     202    /* send_packet emits error message itself if it detects failure */
     203    send_packet(&packet, /*force_bcast:*/ 0);
     204}
     205
     206/* NOINLINE: limit stack usage in caller */
     207static NOINLINE void send_NAK(struct dhcp_packet *oldpacket)
     208{
     209    struct dhcp_packet packet;
     210
     211    init_packet(&packet, oldpacket, DHCPNAK);
     212
     213    log1("Sending NAK");
     214    send_packet(&packet, /*force_bcast:*/ 1);
     215}
     216
     217/* NOINLINE: limit stack usage in caller */
     218static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
     219{
     220    struct dhcp_packet packet;
     221    uint32_t lease_time_sec;
     222    struct in_addr addr;
     223    const char *p_host_name;
     224
     225    init_packet(&packet, oldpacket, DHCPACK);
     226    packet.yiaddr = yiaddr;
     227
     228    lease_time_sec = select_lease_time(oldpacket);
     229    udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
     230
     231    add_server_options(&packet);
     232
     233    addr.s_addr = yiaddr;
     234    bb_info_msg("Sending ACK to %s", inet_ntoa(addr));
     235    send_packet(&packet, /*force_bcast:*/ 0);
     236
     237    p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
     238    add_lease(packet.chaddr, packet.yiaddr,
     239        lease_time_sec,
     240        p_host_name,
     241        p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
     242    );
     243    if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
     244        /* rewrite the file with leases at every new acceptance */
     245        write_leases();
     246    }
     247}
     248
     249/* NOINLINE: limit stack usage in caller */
     250static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
     251{
     252    struct dhcp_packet packet;
     253
     254    /* "If a client has obtained a network address through some other means
     255     * (e.g., manual configuration), it may use a DHCPINFORM request message
     256     * to obtain other local configuration parameters.  Servers receiving a
     257     * DHCPINFORM message construct a DHCPACK message with any local
     258     * configuration parameters appropriate for the client without:
     259     * allocating a new address, checking for an existing binding, filling
     260     * in 'yiaddr' or including lease time parameters.  The servers SHOULD
     261     * unicast the DHCPACK reply to the address given in the 'ciaddr' field
     262     * of the DHCPINFORM message.
     263     * ...
     264     * The server responds to a DHCPINFORM message by sending a DHCPACK
     265     * message directly to the address given in the 'ciaddr' field
     266     * of the DHCPINFORM message.  The server MUST NOT send a lease
     267     * expiration time to the client and SHOULD NOT fill in 'yiaddr'."
     268     */
     269//TODO: do a few sanity checks: is ciaddr set?
     270//Better yet: is ciaddr == IP source addr?
     271    init_packet(&packet, oldpacket, DHCPACK);
     272    add_server_options(&packet);
     273
     274    send_packet(&packet, /*force_bcast:*/ 0);
     275}
    17276
    18277
    19278/* globals */
    20 struct dhcpOfferedAddr *leases;
    21 struct server_config_t server_config;
    22 
    23 
    24 int udhcpd_main(int argc, char **argv);
    25 int udhcpd_main(int argc, char **argv)
     279struct dyn_lease *g_leases;
     280/* struct server_config_t server_config is in bb_common_bufsiz1 */
     281
     282
     283int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     284int udhcpd_main(int argc UNUSED_PARAM, char **argv)
    26285{
    27286    fd_set rfds;
    28     struct timeval tv;
    29     int server_socket = -1, bytes, retval, max_sock;
    30     struct dhcpMessage packet;
    31     uint8_t *state, *server_id, *requested;
    32     uint32_t server_id_align, requested_align, static_lease_ip;
     287    int server_socket = -1, retval, max_sock;
     288    struct dhcp_packet packet;
     289    uint8_t *state;
     290    uint32_t static_lease_nip;
    33291    unsigned timeout_end;
    34292    unsigned num_ips;
    35293    unsigned opt;
    36294    struct option_set *option;
    37     struct dhcpOfferedAddr *lease, static_lease;
    38 
    39     opt = getopt32(argv, "fS");
    40     argv += optind;
    41 
     295    struct dyn_lease *lease, fake_lease;
     296    IF_FEATURE_UDHCP_PORT(char *str_P;)
     297
     298#if ENABLE_FEATURE_UDHCP_PORT
     299    SERVER_PORT = 67;
     300    CLIENT_PORT = 68;
     301#endif
     302
     303#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     304    opt_complementary = "vv";
     305#endif
     306    opt = getopt32(argv, "fSv"
     307        IF_FEATURE_UDHCP_PORT("P:", &str_P)
     308#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     309        , &dhcp_verbose
     310#endif
     311        );
    42312    if (!(opt & 1)) { /* no -f */
    43313        bb_daemonize_or_rexec(0, argv);
    44         logmode &= ~LOGMODE_STDIO;
    45     }
    46 
     314        logmode = LOGMODE_NONE;
     315    }
     316    /* update argv after the possible vfork+exec in daemonize */
     317    argv += optind;
    47318    if (opt & 2) { /* -S */
    48         openlog(applet_name, LOG_PID, LOG_LOCAL0);
     319        openlog(applet_name, LOG_PID, LOG_DAEMON);
    49320        logmode |= LOGMODE_SYSLOG;
    50321    }
    51 
     322#if ENABLE_FEATURE_UDHCP_PORT
     323    if (opt & 8) { /* -P */
     324        SERVER_PORT = xatou16(str_P);
     325        CLIENT_PORT = SERVER_PORT + 1;
     326    }
     327#endif
    52328    /* Would rather not do read_config before daemonization -
    53329     * otherwise NOMMU machines will parse config twice */
     
    61337    /* Create pidfile */
    62338    write_pidfile(server_config.pidfile);
    63     /* if (!..) bb_perror_msg("cannot create pidfile %s", pidfile); */
    64 
    65     bb_info_msg("%s (v%s) started", applet_name, BB_VER);
    66 
    67     option = find_option(server_config.options, DHCP_LEASE_TIME);
    68     server_config.lease = LEASE_TIME;
     339    /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */
     340
     341    bb_info_msg("%s (v"BB_VER") started", applet_name);
     342
     343    option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME);
     344    server_config.max_lease_sec = DEFAULT_LEASE_TIME;
    69345    if (option) {
    70         memcpy(&server_config.lease, option->data + 2, 4);
    71         server_config.lease = ntohl(server_config.lease);
     346        move_from_unaligned32(server_config.max_lease_sec, option->data + OPT_DATA);
     347        server_config.max_lease_sec = ntohl(server_config.max_lease_sec);
    72348    }
    73349
     
    80356    }
    81357
    82     leases = xzalloc(server_config.max_leases * sizeof(*leases));
     358    g_leases = xzalloc(server_config.max_leases * sizeof(g_leases[0]));
    83359    read_leases(server_config.lease_file);
    84360
    85     if (read_interface(server_config.interface, &server_config.ifindex,
    86                &server_config.server, server_config.arp)) {
     361    if (udhcp_read_interface(server_config.interface,
     362            &server_config.ifindex,
     363            &server_config.server_nip,
     364            server_config.server_mac)
     365    ) {
    87366        retval = 1;
    88367        goto ret;
     
    94373    timeout_end = monotonic_sec() + server_config.auto_time;
    95374    while (1) { /* loop until universe collapses */
     375        int bytes;
     376        struct timeval tv;
     377        uint8_t *server_id_opt;
     378        uint8_t *requested_opt;
     379        uint32_t requested_nip = requested_nip; /* for compiler */
    96380
    97381        if (server_socket < 0) {
    98             server_socket = listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
     382            server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
    99383                    server_config.interface);
    100384        }
     
    116400        }
    117401        if (retval < 0 && errno != EINTR) {
    118             DEBUG("error on select");
     402            log1("Error on select");
    119403            continue;
    120404        }
     
    122406        switch (udhcp_sp_read(&rfds)) {
    123407        case SIGUSR1:
    124             bb_info_msg("Received a SIGUSR1");
     408            bb_info_msg("Received SIGUSR1");
    125409            write_leases();
    126410            /* why not just reset the timeout, eh */
     
    128412            continue;
    129413        case SIGTERM:
    130             bb_info_msg("Received a SIGTERM");
     414            bb_info_msg("Received SIGTERM");
    131415            goto ret0;
    132         case 0: break;      /* no signal */
    133         default: continue;  /* signal or error (probably EINTR) */
    134         }
    135 
    136         bytes = udhcp_get_packet(&packet, server_socket); /* this waits for a packet - idle */
     416        case 0: /* no signal: read a packet */
     417            break;
     418        default: /* signal or error (probably EINTR): back to select */
     419            continue;
     420        }
     421
     422        bytes = udhcp_recv_kernel_packet(&packet, server_socket);
    137423        if (bytes < 0) {
     424            /* bytes can also be -2 ("bad packet data") */
    138425            if (bytes == -1 && errno != EINTR) {
    139                 DEBUG("error on read, %s, reopening socket", strerror(errno));
     426                log1("Read error: %s, reopening socket", strerror(errno));
    140427                close(server_socket);
    141428                server_socket = -1;
     
    143430            continue;
    144431        }
    145 
    146         state = get_option(&packet, DHCP_MESSAGE_TYPE);
    147         if (state == NULL) {
    148             bb_error_msg("cannot get option from packet, ignoring");
    149             continue;
    150         }
    151 
    152         /* Look for a static lease */
    153         static_lease_ip = getIpByMac(server_config.static_leases, &packet.chaddr);
    154 
    155         if (static_lease_ip) {
    156             bb_info_msg("Found static lease: %x", static_lease_ip);
    157 
    158             memcpy(&static_lease.chaddr, &packet.chaddr, 16);
    159             static_lease.yiaddr = static_lease_ip;
    160             static_lease.expires = 0;
    161 
    162             lease = &static_lease;
     432        if (packet.hlen != 6) {
     433            bb_error_msg("MAC length != 6, ignoring packet");
     434            continue;
     435        }
     436        if (packet.op != BOOTREQUEST) {
     437            bb_error_msg("not a REQUEST, ignoring packet");
     438            continue;
     439        }
     440        state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
     441        if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) {
     442            bb_error_msg("no or bad message type option, ignoring packet");
     443            continue;
     444        }
     445
     446        /* Look for a static/dynamic lease */
     447        static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr);
     448        if (static_lease_nip) {
     449            bb_info_msg("Found static lease: %x", static_lease_nip);
     450            memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
     451            fake_lease.lease_nip = static_lease_nip;
     452            fake_lease.expires = 0;
     453            lease = &fake_lease;
    163454        } else {
    164             lease = find_lease_by_chaddr(packet.chaddr);
     455            lease = find_lease_by_mac(packet.chaddr);
     456        }
     457
     458        /* Get REQUESTED_IP and SERVER_ID if present */
     459        server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID);
     460        if (server_id_opt) {
     461            uint32_t server_id_net;
     462            move_from_unaligned32(server_id_net, server_id_opt);
     463            if (server_id_net != server_config.server_nip) {
     464                /* client talks to somebody else */
     465                log1("server ID doesn't match, ignoring");
     466                continue;
     467            }
     468        }
     469        requested_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP);
     470        if (requested_opt) {
     471            move_from_unaligned32(requested_nip, requested_opt);
    165472        }
    166473
    167474        switch (state[0]) {
     475
    168476        case DHCPDISCOVER:
    169             DEBUG("Received DISCOVER");
    170 
    171             if (sendOffer(&packet) < 0) {
    172                 bb_error_msg("send OFFER failed");
     477            log1("Received DISCOVER");
     478
     479            send_offer(&packet, static_lease_nip, lease);
     480            break;
     481
     482        case DHCPREQUEST:
     483            log1("Received REQUEST");
     484/* RFC 2131:
     485
     486o DHCPREQUEST generated during SELECTING state:
     487
     488   Client inserts the address of the selected server in 'server
     489   identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
     490   filled in with the yiaddr value from the chosen DHCPOFFER.
     491
     492   Note that the client may choose to collect several DHCPOFFER
     493   messages and select the "best" offer.  The client indicates its
     494   selection by identifying the offering server in the DHCPREQUEST
     495   message.  If the client receives no acceptable offers, the client
     496   may choose to try another DHCPDISCOVER message.  Therefore, the
     497   servers may not receive a specific DHCPREQUEST from which they can
     498   decide whether or not the client has accepted the offer.
     499
     500o DHCPREQUEST generated during INIT-REBOOT state:
     501
     502   'server identifier' MUST NOT be filled in, 'requested IP address'
     503   option MUST be filled in with client's notion of its previously
     504   assigned address. 'ciaddr' MUST be zero. The client is seeking to
     505   verify a previously allocated, cached configuration. Server SHOULD
     506   send a DHCPNAK message to the client if the 'requested IP address'
     507   is incorrect, or is on the wrong network.
     508
     509   Determining whether a client in the INIT-REBOOT state is on the
     510   correct network is done by examining the contents of 'giaddr', the
     511   'requested IP address' option, and a database lookup. If the DHCP
     512   server detects that the client is on the wrong net (i.e., the
     513   result of applying the local subnet mask or remote subnet mask (if
     514   'giaddr' is not zero) to 'requested IP address' option value
     515   doesn't match reality), then the server SHOULD send a DHCPNAK
     516   message to the client.
     517
     518   If the network is correct, then the DHCP server should check if
     519   the client's notion of its IP address is correct. If not, then the
     520   server SHOULD send a DHCPNAK message to the client. If the DHCP
     521   server has no record of this client, then it MUST remain silent,
     522   and MAY output a warning to the network administrator. This
     523   behavior is necessary for peaceful coexistence of non-
     524   communicating DHCP servers on the same wire.
     525
     526   If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on
     527   the same subnet as the server.  The server MUST broadcast the
     528   DHCPNAK message to the 0xffffffff broadcast address because the
     529   client may not have a correct network address or subnet mask, and
     530   the client may not be answering ARP requests.
     531
     532   If 'giaddr' is set in the DHCPREQUEST message, the client is on a
     533   different subnet.  The server MUST set the broadcast bit in the
     534   DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
     535   client, because the client may not have a correct network address
     536   or subnet mask, and the client may not be answering ARP requests.
     537
     538o DHCPREQUEST generated during RENEWING state:
     539
     540   'server identifier' MUST NOT be filled in, 'requested IP address'
     541   option MUST NOT be filled in, 'ciaddr' MUST be filled in with
     542   client's IP address. In this situation, the client is completely
     543   configured, and is trying to extend its lease. This message will
     544   be unicast, so no relay agents will be involved in its
     545   transmission.  Because 'giaddr' is therefore not filled in, the
     546   DHCP server will trust the value in 'ciaddr', and use it when
     547   replying to the client.
     548
     549   A client MAY choose to renew or extend its lease prior to T1.  The
     550   server may choose not to extend the lease (as a policy decision by
     551   the network administrator), but should return a DHCPACK message
     552   regardless.
     553
     554o DHCPREQUEST generated during REBINDING state:
     555
     556   'server identifier' MUST NOT be filled in, 'requested IP address'
     557   option MUST NOT be filled in, 'ciaddr' MUST be filled in with
     558   client's IP address. In this situation, the client is completely
     559   configured, and is trying to extend its lease. This message MUST
     560   be broadcast to the 0xffffffff IP broadcast address.  The DHCP
     561   server SHOULD check 'ciaddr' for correctness before replying to
     562   the DHCPREQUEST.
     563
     564   The DHCPREQUEST from a REBINDING client is intended to accommodate
     565   sites that have multiple DHCP servers and a mechanism for
     566   maintaining consistency among leases managed by multiple servers.
     567   A DHCP server MAY extend a client's lease only if it has local
     568   administrative authority to do so.
     569*/
     570            if (!requested_opt) {
     571                requested_nip = packet.ciaddr;
     572                if (requested_nip == 0) {
     573                    log1("no requested IP and no ciaddr, ignoring");
     574                    break;
     575                }
     576            }
     577            if (lease && requested_nip == lease->lease_nip) {
     578                /* client requested or configured IP matches the lease.
     579                 * ACK it, and bump lease expiration time. */
     580                send_ACK(&packet, lease->lease_nip);
     581                break;
     582            }
     583            if (server_id_opt) {
     584                /* client was talking specifically to us.
     585                 * "No, we don't have this IP for you". */
     586                send_NAK(&packet);
    173587            }
    174588            break;
    175         case DHCPREQUEST:
    176             DEBUG("received REQUEST");
    177 
    178             requested = get_option(&packet, DHCP_REQUESTED_IP);
    179             server_id = get_option(&packet, DHCP_SERVER_ID);
    180 
    181             if (requested) memcpy(&requested_align, requested, 4);
    182             if (server_id) memcpy(&server_id_align, server_id, 4);
    183 
    184             if (lease) {
    185                 if (server_id) {
    186                     /* SELECTING State */
    187                     DEBUG("server_id = %08x", ntohl(server_id_align));
    188                     if (server_id_align == server_config.server && requested
    189                      && requested_align == lease->yiaddr
    190                     ) {
    191                         sendACK(&packet, lease->yiaddr);
    192                     }
    193                 } else if (requested) {
    194                     /* INIT-REBOOT State */
    195                     if (lease->yiaddr == requested_align)
    196                         sendACK(&packet, lease->yiaddr);
    197                     else
    198                         sendNAK(&packet);
    199                 } else if (lease->yiaddr == packet.ciaddr) {
    200                     /* RENEWING or REBINDING State */
    201                     sendACK(&packet, lease->yiaddr);
    202                 } else {
    203                     /* don't know what to do!!!! */
    204                     sendNAK(&packet);
    205                 }
    206 
    207             /* what to do if we have no record of the client */
    208             } else if (server_id) {
    209                 /* SELECTING State */
    210 
    211             } else if (requested) {
    212                 /* INIT-REBOOT State */
    213                 lease = find_lease_by_yiaddr(requested_align);
    214                 if (lease) {
    215                     if (lease_expired(lease)) {
    216                         /* probably best if we drop this lease */
    217                         memset(lease->chaddr, 0, 16);
    218                     /* make some contention for this address */
    219                     } else
    220                         sendNAK(&packet);
    221                 } else {
    222                     uint32_t r = ntohl(requested_align);
    223                     if (r < server_config.start_ip
    224                          || r > server_config.end_ip
    225                     ) {
    226                         sendNAK(&packet);
    227                     }
    228                     /* else remain silent */
    229                 }
    230 
    231             } else {
    232                 /* RENEWING or REBINDING State */
     589
     590        case DHCPDECLINE:
     591            /* RFC 2131:
     592             * "If the server receives a DHCPDECLINE message,
     593             * the client has discovered through some other means
     594             * that the suggested network address is already
     595             * in use. The server MUST mark the network address
     596             * as not available and SHOULD notify the local
     597             * sysadmin of a possible configuration problem."
     598             *
     599             * SERVER_ID must be present,
     600             * REQUESTED_IP must be present,
     601             * chaddr must be filled in,
     602             * ciaddr must be 0 (we do not check this)
     603             */
     604            log1("Received DECLINE");
     605            if (server_id_opt
     606             && requested_opt
     607             && lease  /* chaddr matches this lease */
     608             && requested_nip == lease->lease_nip
     609            ) {
     610                memset(lease->lease_mac, 0, sizeof(lease->lease_mac));
     611                lease->expires = time(NULL) + server_config.decline_time;
    233612            }
    234613            break;
    235         case DHCPDECLINE:
    236             DEBUG("Received DECLINE");
    237             if (lease) {
    238                 memset(lease->chaddr, 0, 16);
    239                 lease->expires = time(0) + server_config.decline_time;
     614
     615        case DHCPRELEASE:
     616            /* "Upon receipt of a DHCPRELEASE message, the server
     617             * marks the network address as not allocated."
     618             *
     619             * SERVER_ID must be present,
     620             * REQUESTED_IP must not be present (we do not check this),
     621             * chaddr must be filled in,
     622             * ciaddr must be filled in
     623             */
     624            log1("Received RELEASE");
     625            if (server_id_opt
     626             && lease  /* chaddr matches this lease */
     627             && packet.ciaddr == lease->lease_nip
     628            ) {
     629                lease->expires = time(NULL);
    240630            }
    241631            break;
    242         case DHCPRELEASE:
    243             DEBUG("Received RELEASE");
    244             if (lease)
    245                 lease->expires = time(0);
    246             break;
     632
    247633        case DHCPINFORM:
    248             DEBUG("Received INFORM");
     634            log1("Received INFORM");
    249635            send_inform(&packet);
    250636            break;
    251         default:
    252             bb_info_msg("Unsupported DHCP message (%02x) - ignoring", state[0]);
    253637        }
    254638    }
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcpd.h

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* dhcpd.h */
    3 #ifndef _DHCPD_H
    4 #define _DHCPD_H
     2/*
     3 * Licensed under GPLv2, see file LICENSE in this source tree.
     4 */
     5#ifndef UDHCP_DHCPD_H
     6#define UDHCP_DHCPD_H 1
    57
    6 /************************************/
    7 /* Defaults _you_ may want to tweak */
    8 /************************************/
     8PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
    99
    10 /* the period of time the client is allowed to use that address */
    11 #define LEASE_TIME              (60*60*24*10) /* 10 days of seconds */
    12 #define LEASES_FILE     "/var/lib/misc/udhcpd.leases"
    13 
    14 /* where to find the DHCP server configuration file */
     10/* Defaults you may want to tweak */
     11/* Default max_lease_sec */
     12#define DEFAULT_LEASE_TIME      (60*60*24 * 10)
     13#define LEASES_FILE             CONFIG_DHCPD_LEASES_FILE
     14/* Where to find the DHCP server configuration file */
    1515#define DHCPD_CONF_FILE         "/etc/udhcpd.conf"
    1616
    17 struct option_set {
    18     uint8_t *data;
    19     struct option_set *next;
    20 };
    2117
    2218struct static_lease {
    2319    struct static_lease *next;
    24     uint8_t *mac;
    25     uint32_t *ip;
     20    uint32_t nip;
     21    uint8_t mac[6];
    2622};
    2723
    2824struct server_config_t {
    29     uint32_t server;                /* Our IP, in network order */
     25    char *interface;                /* interface to use */
     26//TODO: ifindex, server_nip, server_mac
     27// are obtained from interface name.
     28// Instead of querying them *once*, create update_server_network_data_cache()
     29// and call it before any usage of these fields.
     30// update_server_network_data_cache() must re-query data
     31// if more than N seconds have passed after last use.
     32    int ifindex;
     33    uint32_t server_nip;
     34#if ENABLE_FEATURE_UDHCP_PORT
     35    uint16_t port;
     36#endif
     37    uint8_t server_mac[6];          /* our MAC address (used only for ARP probing) */
     38    struct option_set *options;     /* list of DHCP options loaded from the config file */
    3039    /* start,end are in host order: we need to compare start <= ip <= end */
    31     uint32_t start_ip;              /* Start address of leases, in host order */
    32     uint32_t end_ip;                /* End of leases, in host order */
    33     struct option_set *options;     /* List of DHCP options loaded from the config file */
    34     char *interface;                /* The name of the interface to use */
    35     int ifindex;                    /* Index number of the interface to use */
    36     uint8_t arp[6];                 /* Our arp address */
    37     char remaining;                 /* should the lease file be interpreted as lease time remaining, or
    38                                      * as the time the lease expires */
    39     uint32_t lease;                 /* lease time in seconds (host order) */
    40     uint32_t max_leases;            /* maximum number of leases (including reserved address) */
     40    uint32_t start_ip;              /* start address of leases, in host order */
     41    uint32_t end_ip;                /* end of leases, in host order */
     42    uint32_t max_lease_sec;         /* maximum lease time (host order) */
     43    uint32_t min_lease_sec;         /* minimum lease time a client can request */
     44    uint32_t max_leases;            /* maximum number of leases (including reserved addresses) */
    4145    uint32_t auto_time;             /* how long should udhcpd wait before writing a config file.
    4246                                     * if this is zero, it will only write one on SIGUSR1 */
     
    4549    uint32_t conflict_time;         /* how long an arp conflict offender is leased for */
    4650    uint32_t offer_time;            /* how long an offered address is reserved */
    47     uint32_t min_lease;             /* minimum lease a client can request */
     51    uint32_t siaddr_nip;            /* "next server" bootp option */
    4852    char *lease_file;
    4953    char *pidfile;
    50     char *notify_file;              /* What to run whenever leases are written */
    51     uint32_t siaddr;                /* next server bootp option */
     54    char *notify_file;              /* what to run whenever leases are written */
    5255    char *sname;                    /* bootp server name */
    5356    char *boot_file;                /* bootp boot file option */
    5457    struct static_lease *static_leases; /* List of ip/mac pairs to assign static leases */
    55 };
     58} FIX_ALIASING;
    5659
    57 extern struct server_config_t server_config;
    58 extern struct dhcpOfferedAddr *leases;
     60#define server_config (*(struct server_config_t*)&bb_common_bufsiz1)
     61/* client_config sits in 2nd half of bb_common_bufsiz1 */
     62
     63#if ENABLE_FEATURE_UDHCP_PORT
     64#define SERVER_PORT (server_config.port)
     65#else
     66#define SERVER_PORT 67
     67#endif
    5968
    6069
    61 /*** leases.h ***/
     70typedef uint32_t leasetime_t;
     71typedef int32_t signed_leasetime_t;
    6272
    63 struct dhcpOfferedAddr {
    64     uint8_t chaddr[16];
    65     uint32_t yiaddr;    /* network order */
    66     uint32_t expires;   /* host order */
    67 };
     73struct dyn_lease {
     74    /* Unix time when lease expires. Kept in memory in host order.
     75     * When written to file, converted to network order
     76     * and adjusted (current time subtracted) */
     77    leasetime_t expires;
     78    /* "nip": IP in network order */
     79    uint32_t lease_nip;
     80    /* We use lease_mac[6], since e.g. ARP probing uses
     81     * only 6 first bytes anyway. We check received dhcp packets
     82     * that their hlen == 6 and thus chaddr has only 6 significant bytes
     83     * (dhcp packet has chaddr[16], not [6])
     84     */
     85    uint8_t lease_mac[6];
     86    char hostname[20];
     87    uint8_t pad[2];
     88    /* total size is a multiply of 4 */
     89} PACKED;
    6890
    69 struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease);
    70 int lease_expired(struct dhcpOfferedAddr *lease);
    71 struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr);
    72 struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr);
    73 uint32_t find_address(int check_expired);
     91extern struct dyn_lease *g_leases;
     92
     93struct dyn_lease *add_lease(
     94        const uint8_t *chaddr, uint32_t yiaddr,
     95        leasetime_t leasetime,
     96        const char *hostname, int hostname_len
     97        ) FAST_FUNC;
     98int is_expired_lease(struct dyn_lease *lease) FAST_FUNC;
     99struct dyn_lease *find_lease_by_mac(const uint8_t *mac) FAST_FUNC;
     100struct dyn_lease *find_lease_by_nip(uint32_t nip) FAST_FUNC;
     101uint32_t find_free_or_expired_nip(const uint8_t *safe_mac) FAST_FUNC;
    74102
    75103
    76 /*** static_leases.h ***/
    77 
    78 /* Config file will pass static lease info to this function which will add it
    79  * to a data structure that can be searched later */
    80 int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip);
    81 /* Check to see if a mac has an associated static lease */
    82 uint32_t getIpByMac(struct static_lease *lease_struct, void *arg);
    83 /* Check to see if an ip is reserved as a static ip */
    84 uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip);
     104/* Config file parser will pass static lease info to this function
     105 * which will add it to a data structure that can be searched later */
     106void add_static_lease(struct static_lease **st_lease_pp, uint8_t *mac, uint32_t nip) FAST_FUNC;
     107/* Find static lease IP by mac */
     108uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *arg) FAST_FUNC;
     109/* Check to see if an IP is reserved as a static IP */
     110int is_nip_reserved(struct static_lease *st_lease, uint32_t nip) FAST_FUNC;
    85111/* Print out static leases just to check what's going on (debug code) */
    86 void printStaticLeases(struct static_lease **lease_struct);
     112#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
     113void log_static_leases(struct static_lease **st_lease_pp) FAST_FUNC;
     114#else
     115# define log_static_leases(st_lease_pp) ((void)0)
     116#endif
    87117
    88118
    89 /*** serverpacket.h ***/
    90 
    91 int sendOffer(struct dhcpMessage *oldpacket);
    92 int sendNAK(struct dhcpMessage *oldpacket);
    93 int sendACK(struct dhcpMessage *oldpacket, uint32_t yiaddr);
    94 int send_inform(struct dhcpMessage *oldpacket);
     119void read_config(const char *file) FAST_FUNC;
     120void write_leases(void) FAST_FUNC;
     121void read_leases(const char *file) FAST_FUNC;
    95122
    96123
    97 /*** files.h ***/
    98 
    99 int read_config(const char *file);
    100 void write_leases(void);
    101 void read_leases(const char *file);
    102 struct option_set *find_option(struct option_set *opt_list, char code);
    103 
     124POP_SAVED_FUNCTION_VISIBILITY
    104125
    105126#endif
  • branches/2.2.9/mindi-busybox/networking/udhcp/dhcprelay.c

    r1765 r2725  
    22/* Port to Busybox Copyright (C) 2006 Jesse Dutton <jessedutton@gmail.com>
    33 *
    4  * Licensed under GPL v2, see file LICENSE in this tarball for details.
     4 * Licensed under GPLv2, see file LICENSE in this source tree.
    55 *
    66 * DHCP Relay for 'DHCPv4 Configuration of IPSec Tunnel Mode' support
     
    1010 * Upstream has GPL v2 or later
    1111 */
    12 
    1312#include "common.h"
    14 #include "dhcpd.h"
    15 #include "options.h"
    16 
    17 /* constants */
    18 #define SELECT_TIMEOUT 5 /* select timeout in sec. */
    19 #define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */
    20 #define MAX_INTERFACES 9
    21 
     13
     14#define SERVER_PORT    67
     15
     16/* lifetime of an xid entry in sec. */
     17#define MAX_LIFETIME   2*60
     18/* select timeout in sec. */
     19#define SELECT_TIMEOUT (MAX_LIFETIME / 8)
    2220
    2321/* This list holds information about clients. The xid_* functions manipulate this list. */
    24 static struct xid_item {
     22struct xid_item {
     23    unsigned timestamp;
     24    int client;
    2525    uint32_t xid;
    2626    struct sockaddr_in ip;
    27     int client;
    28     time_t timestamp;
    2927    struct xid_item *next;
    30 } dhcprelay_xid_list = {0, {0}, 0, 0, NULL};
    31 
     28};
     29
     30#define dhcprelay_xid_list (*(struct xid_item*)&bb_common_bufsiz1)
    3231
    3332static struct xid_item *xid_add(uint32_t xid, struct sockaddr_in *ip, int client)
     
    4241    item->xid = xid;
    4342    item->client = client;
    44     item->timestamp = time(NULL);
     43    item->timestamp = monotonic_sec();
    4544    item->next = dhcprelay_xid_list.next;
    4645    dhcprelay_xid_list.next = item;
     
    5352    struct xid_item *item = dhcprelay_xid_list.next;
    5453    struct xid_item *last = &dhcprelay_xid_list;
    55     time_t current_time = time(NULL);
     54    unsigned current_time = monotonic_sec();
    5655
    5756    while (item != NULL) {
     
    7271    while (item != NULL) {
    7372        if (item->xid == xid) {
    74             return item;
     73            break;
    7574        }
    7675        item = item->next;
    7776    }
    78     return NULL;
     77    return item;
    7978}
    8079
     
    10099 * returns the message type on success, -1 otherwise
    101100 */
    102 static int get_dhcp_packet_type(struct dhcpMessage *p)
     101static int get_dhcp_packet_type(struct dhcp_packet *p)
    103102{
    104103    uint8_t *op;
     
    108107        return -1;
    109108    /* get message type option */
    110     op = get_option(p, DHCP_MESSAGE_TYPE);
     109    op = udhcp_get_option(p, DHCP_MESSAGE_TYPE);
    111110    if (op != NULL)
    112111        return op[0];
     
    115114
    116115/**
    117  * signal_handler - handles signals ;-)
    118  * sig - sent signal
    119  */
    120 static smallint dhcprelay_stopflag;
    121 
    122 static void dhcprelay_signal_handler(int sig)
    123 {
    124     dhcprelay_stopflag = 1;
    125 }
    126 
    127 /**
    128  * get_client_devices - parses the devices list
    129  * dev_list - comma separated list of devices
     116 * make_iface_list - parses client/server interface names
    130117 * returns array
    131118 */
    132 static char **get_client_devices(char *dev_list, int *client_number)
    133 {
    134     char *s, *list, **client_dev;
     119static char **make_iface_list(char **client_and_server_ifaces, int *client_number)
     120{
     121    char *s, **iface_list;
    135122    int i, cn;
    136123
    137     /* copy list */
    138     list = xstrdup(dev_list);
    139     if (list == NULL) return NULL;
    140 
    141124    /* get number of items */
    142     for (s = dev_list, cn = 1; *s; s++)
     125    cn = 2; /* 1 server iface + at least 1 client one */
     126    s = client_and_server_ifaces[0]; /* list of client ifaces */
     127    while (*s) {
    143128        if (*s == ',')
    144129            cn++;
    145 
    146     client_dev = xzalloc(cn * sizeof(*client_dev));
    147 
    148     /* parse list */
    149     s = strtok(list, ",");
    150     i = 0;
    151     while (s != NULL) {
    152         client_dev[i++] = xstrdup(s);
    153         s = strtok(NULL, ",");
    154     }
    155 
    156     /* free copy and exit */
    157     free(list);
     130        s++;
     131    }
    158132    *client_number = cn;
    159     return client_dev;
    160 }
    161 
    162 
    163 /* Creates listen sockets (in fds) and returns the number allocated. */
    164 static int init_sockets(char **client, int num_clients,
    165             char *server, int *fds, int *max_socket)
    166 {
    167     int i;
    168 
    169     /* talk to real server on bootps */
    170     fds[0] = listen_socket(/*INADDR_ANY,*/ 67, server);
    171     *max_socket = fds[0];
    172 
    173     /* array starts at 1 since server is 0 */
    174     num_clients++;
    175 
    176     for (i = 1; i < num_clients; i++) {
    177         /* listen for clients on bootps */
    178         fds[i] = listen_socket(/*NADDR_ANY,*/ 67, client[i-1]);
    179         if (fds[i] > *max_socket)
    180             *max_socket = fds[i];
    181     }
    182 
    183     return i;
    184 }
    185 
     133
     134    /* create vector of pointers */
     135    iface_list = xzalloc(cn * sizeof(iface_list[0]));
     136
     137    iface_list[0] = client_and_server_ifaces[1]; /* server iface */
     138
     139    i = 1;
     140    s = xstrdup(client_and_server_ifaces[0]); /* list of client ifaces */
     141    goto store_client_iface_name;
     142
     143    while (i < cn) {
     144        if (*s++ == ',') {
     145            s[-1] = '\0';
     146 store_client_iface_name:
     147            iface_list[i++] = s;
     148        }
     149    }
     150
     151    return iface_list;
     152}
     153
     154/* Creates listen sockets (in fds) bound to client and server ifaces,
     155 * and returns numerically max fd.
     156 */
     157static int init_sockets(char **iface_list, int num_clients, int *fds)
     158{
     159    int i, n;
     160
     161    n = 0;
     162    for (i = 0; i < num_clients; i++) {
     163        fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, iface_list[i]);
     164        if (n < fds[i])
     165            n = fds[i];
     166    }
     167    return n;
     168}
     169
     170static int sendto_ip4(int sock, const void *msg, int msg_len, struct sockaddr_in *to)
     171{
     172    int err;
     173
     174    errno = 0;
     175    err = sendto(sock, msg, msg_len, 0, (struct sockaddr*) to, sizeof(*to));
     176    err -= msg_len;
     177    if (err)
     178        bb_perror_msg("sendto");
     179    return err;
     180}
    186181
    187182/**
    188  * pass_on() - forwards dhcp packets from client to server
     183 * pass_to_server() - forwards dhcp packets from client to server
    189184 * p - packet to send
    190185 * client - number of the client
    191186 */
    192 static void pass_on(struct dhcpMessage *p, int packet_len, int client, int *fds,
     187static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds,
    193188            struct sockaddr_in *client_addr, struct sockaddr_in *server_addr)
    194189{
    195     int res, type;
    196     struct xid_item *item;
     190    int type;
    197191
    198192    /* check packet_type */
     
    206200
    207201    /* create new xid entry */
    208     item = xid_add(p->xid, client_addr, client);
    209 
    210     /* forward request to LAN (server) */
    211     res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr,
    212             sizeof(struct sockaddr_in));
    213     if (res != packet_len) {
    214         bb_perror_msg("pass_on");
    215         return;
    216     }
     202    xid_add(p->xid, client_addr, client);
     203
     204    /* forward request to server */
     205    /* note that we send from fds[0] which is bound to SERVER_PORT (67).
     206     * IOW: we send _from_ SERVER_PORT! Although this may look strange,
     207     * RFC 1542 not only allows, but prescribes this for BOOTP relays.
     208     */
     209    sendto_ip4(fds[0], p, packet_len, server_addr);
    217210}
    218211
    219212/**
    220  * pass_back() - forwards dhcp packets from server to client
     213 * pass_to_client() - forwards dhcp packets from server to client
    221214 * p - packet to send
    222215 */
    223 static void pass_back(struct dhcpMessage *p, int packet_len, int *fds)
    224 {
    225     int res, type;
     216static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds)
     217{
     218    int type;
    226219    struct xid_item *item;
    227220
     
    238231    }
    239232
     233//TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set!
    240234    if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY))
    241235        item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    242     if (item->client > MAX_INTERFACES)
    243         return;
    244     res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*)(&item->ip),
    245                 sizeof(item->ip));
    246     if (res != packet_len) {
    247         bb_perror_msg("pass_back");
    248         return;
     236
     237    if (sendto_ip4(fds[item->client], p, packet_len, &item->ip) != 0) {
     238        return; /* send error occurred */
    249239    }
    250240
     
    253243}
    254244
    255 static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients,
    256         struct sockaddr_in *server_addr, uint32_t gw_ip)
    257 {
    258     struct dhcpMessage dhcp_msg;
    259     fd_set rfds;
    260     size_t packlen;
    261     socklen_t addr_size;
    262     struct sockaddr_in client_addr;
    263     struct timeval tv;
    264     int i;
    265 
    266     while (!dhcprelay_stopflag) {
     245int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     246int dhcprelay_main(int argc, char **argv)
     247{
     248    struct sockaddr_in server_addr;
     249    char **iface_list;
     250    int *fds;
     251    int num_sockets, max_socket;
     252    uint32_t our_nip;
     253
     254    server_addr.sin_family = AF_INET;
     255    server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
     256    server_addr.sin_port = htons(SERVER_PORT);
     257
     258    /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */
     259    if (argc == 4) {
     260        if (!inet_aton(argv[3], &server_addr.sin_addr))
     261            bb_perror_msg_and_die("bad server IP");
     262    } else if (argc != 3) {
     263        bb_show_usage();
     264    }
     265
     266    iface_list = make_iface_list(argv + 1, &num_sockets);
     267
     268    fds = xmalloc(num_sockets * sizeof(fds[0]));
     269
     270    /* Create sockets and bind one to every iface */
     271    max_socket = init_sockets(iface_list, num_sockets, fds);
     272
     273    /* Get our IP on server_iface */
     274    if (udhcp_read_interface(argv[2], NULL, &our_nip, NULL))
     275        return 1;
     276
     277    /* Main loop */
     278    while (1) {
     279// reinit stuff from time to time? go back to make_iface_list
     280// every N minutes?
     281        fd_set rfds;
     282        struct timeval tv;
     283        int i;
     284
    267285        FD_ZERO(&rfds);
    268286        for (i = 0; i < num_sockets; i++)
     
    271289        tv.tv_usec = 0;
    272290        if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) {
     291            int packlen;
     292            struct dhcp_packet dhcp_msg;
     293
    273294            /* server */
    274295            if (FD_ISSET(fds[0], &rfds)) {
    275                 packlen = udhcp_get_packet(&dhcp_msg, fds[0]);
     296                packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]);
    276297                if (packlen > 0) {
    277                     pass_back(&dhcp_msg, packlen, fds);
     298                    pass_to_client(&dhcp_msg, packlen, fds);
    278299                }
    279300            }
     301
     302            /* clients */
    280303            for (i = 1; i < num_sockets; i++) {
    281                 /* clients */
     304                struct sockaddr_in client_addr;
     305                socklen_t addr_size;
     306
    282307                if (!FD_ISSET(fds[i], &rfds))
    283308                    continue;
    284                 addr_size = sizeof(struct sockaddr_in);
     309
     310                addr_size = sizeof(client_addr);
    285311                packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0,
    286                             (struct sockaddr *)(&client_addr), &addr_size);
     312                        (struct sockaddr *)(&client_addr), &addr_size);
    287313                if (packlen <= 0)
    288314                    continue;
    289                 if (read_interface(clients[i-1], NULL, &dhcp_msg.giaddr, NULL))
    290                     dhcp_msg.giaddr = gw_ip;
    291                 pass_on(&dhcp_msg, packlen, i, fds, &client_addr, server_addr);
     315
     316                /* Get our IP on corresponding client_iface */
     317// RFC 1542
     318// 4.1 General BOOTP Processing for Relay Agents
     319// 4.1.1 BOOTREQUEST Messages
     320//   If the relay agent does decide to relay the request, it MUST examine
     321//   the 'giaddr' ("gateway" IP address) field.  If this field is zero,
     322//   the relay agent MUST fill this field with the IP address of the
     323//   interface on which the request was received.  If the interface has
     324//   more than one IP address logically associated with it, the relay
     325//   agent SHOULD choose one IP address associated with that interface and
     326//   use it consistently for all BOOTP messages it relays.  If the
     327//   'giaddr' field contains some non-zero value, the 'giaddr' field MUST
     328//   NOT be modified.  The relay agent MUST NOT, under any circumstances,
     329//   fill the 'giaddr' field with a broadcast address as is suggested in
     330//   [1] (Section 8, sixth paragraph).
     331
     332// but why? what if server can't route such IP? Client ifaces may be, say, NATed!
     333
     334// 4.1.2 BOOTREPLY Messages
     335//   BOOTP relay agents relay BOOTREPLY messages only to BOOTP clients.
     336//   It is the responsibility of BOOTP servers to send BOOTREPLY messages
     337//   directly to the relay agent identified in the 'giaddr' field.
     338// (yeah right, unless it is impossible... see comment above)
     339//   Therefore, a relay agent may assume that all BOOTREPLY messages it
     340//   receives are intended for BOOTP clients on its directly-connected
     341//   networks.
     342//
     343//   When a relay agent receives a BOOTREPLY message, it should examine
     344//   the BOOTP 'giaddr', 'yiaddr', 'chaddr', 'htype', and 'hlen' fields.
     345//   These fields should provide adequate information for the relay agent
     346//   to deliver the BOOTREPLY message to the client.
     347//
     348//   The 'giaddr' field can be used to identify the logical interface from
     349//   which the reply must be sent (i.e., the host or router interface
     350//   connected to the same network as the BOOTP client).  If the content
     351//   of the 'giaddr' field does not match one of the relay agent's
     352//   directly-connected logical interfaces, the BOOTREPLY messsage MUST be
     353//   silently discarded.
     354                if (udhcp_read_interface(iface_list[i], NULL, &dhcp_msg.gateway_nip, NULL)) {
     355                    /* Fall back to our IP on server iface */
     356// this makes more sense!
     357                    dhcp_msg.gateway_nip = our_nip;
     358                }
     359// maybe dhcp_msg.hops++? drop packets with too many hops (RFC 1542 says 4 or 16)?
     360                pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr);
    292361            }
    293362        }
    294363        xid_expire();
    295     }
    296 }
    297 
    298 int dhcprelay_main(int argc, char **argv);
    299 int dhcprelay_main(int argc, char **argv)
    300 {
    301     int i, num_sockets, max_socket, fds[MAX_INTERFACES];
    302     uint32_t gw_ip;
    303     char **clients;
    304     struct sockaddr_in server_addr;
    305 
    306     server_addr.sin_family = AF_INET;
    307     server_addr.sin_port = htons(67);
    308     if (argc == 4) {
    309         if (!inet_aton(argv[3], &server_addr.sin_addr))
    310             bb_perror_msg_and_die("didn't grok server");
    311     } else if (argc == 3) {
    312         server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
    313     } else {
    314         bb_show_usage();
    315     }
    316     clients = get_client_devices(argv[1], &num_sockets);
    317     if (!clients) return 0;
    318 
    319     signal(SIGTERM, dhcprelay_signal_handler);
    320     signal(SIGQUIT, dhcprelay_signal_handler);
    321     signal(SIGINT, dhcprelay_signal_handler);
    322 
    323     num_sockets = init_sockets(clients, num_sockets, argv[2], fds, &max_socket);
    324 
    325     if (read_interface(argv[2], NULL, &gw_ip, NULL))
    326         return 1;
    327 
    328     dhcprelay_loop(fds, num_sockets, max_socket, clients, &server_addr, gw_ip);
    329 
    330     if (ENABLE_FEATURE_CLEAN_UP) {
    331         for (i = 0; i < num_sockets; i++) {
    332             close(fds[i]);
    333             free(clients[i]);
    334         }
    335     }
    336 
    337     return 0;
    338 }
     364    } /* while (1) */
     365
     366    /* return 0; - not reached */
     367}
  • branches/2.2.9/mindi-busybox/networking/udhcp/domain_codec.c

    r1765 r2725  
    55 * Loosely based on the isc-dhcpd implementation by dhankins@isc.org
    66 *
    7  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
    8  */
    9 
    10 #if ENABLE_FEATURE_RFC3397
    11 
    12 #include "common.h"
    13 #include "options.h"
     7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
     8 */
     9#ifdef DNS_COMPR_TESTING
     10# define FAST_FUNC /* nothing */
     11# define xmalloc malloc
     12# include <stdlib.h>
     13# include <stdint.h>
     14# include <string.h>
     15# include <stdio.h>
     16#else
     17# include "common.h"
     18#endif
    1419
    1520#define NS_MAXDNAME  1025   /* max domain name length */
     
    2025
    2126
    22 /* expand a RFC1035-compressed list of domain names "cstr", of length "clen";
     27/* Expand a RFC1035-compressed list of domain names "cstr", of length "clen";
    2328 * returns a newly allocated string containing the space-separated domains,
    2429 * prefixed with the contents of string pre, or NULL if an error occurs.
    2530 */
    26 char *dname_dec(const uint8_t *cstr, int clen, const char *pre)
    27 {
    28     const uint8_t *c;
    29     int crtpos, retpos, depth, plen = 0, len = 0;
     31char* FAST_FUNC dname_dec(const uint8_t *cstr, int clen, const char *pre)
     32{
     33    char *ret = ret; /* for compiler */
    3034    char *dst = NULL;
    31 
    32     if (!cstr)
    33         return NULL;
    34 
    35     if (pre)
    36         plen = strlen(pre);
    3735
    3836    /* We make two passes over the cstr string. First, we compute
     
    4341     * buffer, then having to check if it's sufficiently large, etc.
    4442     */
    45 
    46     while (!dst) {
    47 
    48         if (len > 0) {  /* second pass? allocate dst buffer and copy pre */
    49             dst = xmalloc(len + plen);
    50             memcpy(dst, pre, plen);
    51         }
     43    while (1) {
     44        /* note: "return NULL" below are leak-safe since
     45         * dst isn't yet allocated */
     46        const uint8_t *c;
     47        unsigned crtpos, retpos, depth, len;
    5248
    5349        crtpos = retpos = depth = len = 0;
    54 
    5550        while (crtpos < clen) {
    5651            c = cstr + crtpos;
    5752
    58             if ((*c & NS_CMPRSFLGS) != 0) { /* pointer */
    59                 if (crtpos + 2 > clen)      /* no offset to jump to? abort */
     53            if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
     54                /* pointer */
     55                if (crtpos + 2 > clen) /* no offset to jump to? abort */
    6056                    return NULL;
    61                 if (retpos == 0)            /* toplevel? save return spot */
     57                if (retpos == 0) /* toplevel? save return spot */
    6258                    retpos = crtpos + 2;
    6359                depth++;
    64                 crtpos = ((*c & 0x3f) << 8) | (*(c + 1) & 0xff); /* jump */
    65             } else if (*c) {            /* label */
    66                 if (crtpos + *c + 1 > clen)     /* label too long? abort */
     60                crtpos = ((c[0] & 0x3f) << 8) | c[1]; /* jump */
     61            } else if (*c) {
     62                /* label */
     63                if (crtpos + *c + 1 > clen) /* label too long? abort */
    6764                    return NULL;
    6865                if (dst)
    69                     memcpy(dst + plen + len, c + 1, *c);
     66                    memcpy(dst + len, c + 1, *c);
    7067                len += *c + 1;
    7168                crtpos += *c + 1;
    7269                if (dst)
    73                     *(dst + plen + len - 1) = '.';
    74             } else {                    /* null: end of current domain name */
    75                 if (retpos == 0) {          /* toplevel? keep going */
     70                    dst[len - 1] = '.';
     71            } else {
     72                /* NUL: end of current domain name */
     73                if (retpos == 0) {
     74                    /* toplevel? keep going */
    7675                    crtpos++;
    77                 } else {                    /* return to toplevel saved spot */
     76                } else {
     77                    /* return to toplevel saved spot */
    7878                    crtpos = retpos;
    7979                    retpos = depth = 0;
    8080                }
    8181                if (dst)
    82                     *(dst + plen + len - 1) = ' ';
    83             }
    84 
    85             if (depth > NS_MAXDNSRCH || /* too many jumps? abort, it's a loop */
    86                 len > NS_MAXDNAME * NS_MAXDNSRCH) /* result too long? abort */
     82                    dst[len - 1] = ' ';
     83            }
     84
     85            if (depth > NS_MAXDNSRCH /* too many jumps? abort, it's a loop */
     86             || len > NS_MAXDNAME * NS_MAXDNSRCH /* result too long? abort */
     87            ) {
    8788                return NULL;
    88         }
    89 
    90         if (!len)           /* expanded string has 0 length? abort */
     89            }
     90        }
     91
     92        if (!len) /* expanded string has 0 length? abort */
    9193            return NULL;
    9294
    93         if (dst)
    94             *(dst + plen + len - 1) = '\0';
    95     }
    96 
    97     return dst;
     95        if (!dst) { /* first pass? */
     96            /* allocate dst buffer and copy pre */
     97            unsigned plen = strlen(pre);
     98            ret = dst = xmalloc(plen + len);
     99            memcpy(dst, pre, plen);
     100            dst += plen;
     101        } else {
     102            dst[len - 1] = '\0';
     103            break;
     104        }
     105    }
     106
     107    return ret;
    98108}
    99109
     
    104114static uint8_t *convert_dname(const char *src)
    105115{
    106     uint8_t c, *res, *lp, *rp;
     116    uint8_t c, *res, *lenptr, *dst;
    107117    int len;
    108118
    109119    res = xmalloc(strlen(src) + 2);
    110     rp = lp = res;
    111     rp++;
     120    dst = lenptr = res;
     121    dst++;
    112122
    113123    for (;;) {
    114124        c = (uint8_t)*src++;
    115         if (c == '.' || c == '\0') {    /* end of label */
    116             len = rp - lp - 1;
     125        if (c == '.' || c == '\0') {  /* end of label */
     126            len = dst - lenptr - 1;
    117127            /* label too long, too short, or two '.'s in a row? abort */
    118128            if (len > NS_MAXLABEL || len == 0 || (c == '.' && *src == '.')) {
     
    120130                return NULL;
    121131            }
    122             *lp = len;
    123             lp = rp++;
    124             if (c == '\0' || *src == '\0')  /* end of dname */
     132            *lenptr = len;
     133            if (c == '\0' || *src == '\0')  /* "" or ".": end of src */
    125134                break;
    126         } else {
    127             if (c >= 0x41 && c <= 0x5A)     /* uppercase? convert to lower */
    128                 c += 0x20;
    129             *rp++ = c;
    130         }
    131     }
    132 
    133     *lp = 0;
    134     if (rp - res > NS_MAXCDNAME) {  /* dname too long? abort */
     135            lenptr = dst++;
     136            continue;
     137        }
     138        if (c >= 'A' && c <= 'Z')  /* uppercase? convert to lower */
     139            c += ('a' - 'A');
     140        *dst++ = c;
     141    }
     142
     143    if (dst - res >= NS_MAXCDNAME) {  /* dname too long? abort */
    135144        free(res);
    136145        return NULL;
    137146    }
     147
     148    *dst = 0;
    138149    return res;
    139150}
    140151
    141 /* returns the offset within cstr at which dname can be found, or -1
    142  */
     152/* Returns the offset within cstr at which dname can be found, or -1 */
    143153static int find_offset(const uint8_t *cstr, int clen, const uint8_t *dname)
    144154{
    145155    const uint8_t *c, *d;
    146     int off, inc;
     156    int off;
    147157
    148158    /* find all labels in cstr */
     
    151161        c = cstr + off;
    152162
    153         if ((*c & NS_CMPRSFLGS) != 0) { /* pointer, skip */
     163        if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS) {  /* pointer, skip */
    154164            off += 2;
    155         } else if (*c) {    /* label, try matching dname */
    156             inc = *c + 1;
     165            continue;
     166        }
     167        if (*c) {  /* label, try matching dname */
    157168            d = dname;
    158             while (*c == *d && memcmp(c + 1, d + 1, *c) == 0) {
    159                 if (*c == 0)    /* match, return offset */
     169            while (1) {
     170                unsigned len1 = *c + 1;
     171                if (memcmp(c, d, len1) != 0)
     172                    break;
     173                if (len1 == 1)  /* at terminating NUL - match, return offset */
    160174                    return off;
    161                 d += *c + 1;
    162                 c += *c + 1;
    163                 if ((*c & NS_CMPRSFLGS) != 0)   /* pointer, jump */
    164                     c = cstr + (((*c & 0x3f) << 8) | (*(c + 1) & 0xff));
    165             }
    166             off += inc;
    167         } else {    /* null, skip */
    168             off++;
    169         }
     175                d += len1;
     176                c += len1;
     177                if ((*c & NS_CMPRSFLGS) == NS_CMPRSFLGS)  /* pointer, jump */
     178                    c = cstr + (((c[0] & 0x3f) << 8) | c[1]);
     179            }
     180            off += cstr[off] + 1;
     181            continue;
     182        }
     183        /* NUL, skip */
     184        off++;
    170185    }
    171186
     
    173188}
    174189
    175 /* computes string to be appended to cstr so that src would be added to
     190/* Computes string to be appended to cstr so that src would be added to
    176191 * the compression (best case, it's a 2-byte pointer to some offset within
    177  * cstr; worst case, it's all of src, converted to rfc3011 format).
     192 * cstr; worst case, it's all of src, converted to <4>host<3>com<0> format).
    178193 * The computed string is returned directly; its length is returned via retlen;
    179194 * NULL and 0, respectively, are returned if an error occurs.
    180195 */
    181 uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen)
     196uint8_t* FAST_FUNC dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen)
    182197{
    183198    uint8_t *d, *dname;
     
    190205    }
    191206
    192     for (d = dname; *d != 0; d += *d + 1) {
    193         off = find_offset(cstr, clen, d);
    194         if (off >= 0) { /* found a match, add pointer and terminate string */
    195             *d++ = NS_CMPRSFLGS;
    196             *d = off;
    197             break;
    198         }
     207    d = dname;
     208    while (*d) {
     209        if (cstr) {
     210            off = find_offset(cstr, clen, d);
     211            if (off >= 0) { /* found a match, add pointer and return */
     212                *d++ = NS_CMPRSFLGS | (off >> 8);
     213                *d = off;
     214                break;
     215            }
     216        }
     217        d += *d + 1;
    199218    }
    200219
     
    203222}
    204223
    205 #endif /* ENABLE_FEATURE_RFC3397 */
     224#ifdef DNS_COMPR_TESTING
     225/* gcc -Wall -DDNS_COMPR_TESTING domain_codec.c -o domain_codec && ./domain_codec */
     226int main(int argc, char **argv)
     227{
     228    int len;
     229    uint8_t *encoded;
     230
     231#define DNAME_DEC(encoded,pre) dname_dec((uint8_t*)(encoded), sizeof(encoded), (pre))
     232    printf("'%s'\n",       DNAME_DEC("\4host\3com\0", "test1:"));
     233    printf("test2:'%s'\n", DNAME_DEC("\4host\3com\0\4host\3com\0", ""));
     234    printf("test3:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\0", ""));
     235    printf("test4:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\5", ""));
     236    printf("test5:'%s'\n", DNAME_DEC("\4host\3com\0\xC0\5\1z\xC0\xA", ""));
     237
     238#define DNAME_ENC(cache,source,lenp) dname_enc((uint8_t*)(cache), sizeof(cache), (source), (lenp))
     239    encoded = dname_enc(NULL, 0, "test.net", &len);
     240    printf("test6:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
     241    encoded = DNAME_ENC("\3net\0", "test.net", &len);
     242    printf("test7:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
     243    encoded = DNAME_ENC("\4test\3net\0", "test.net", &len);
     244    printf("test8:'%s' len:%d\n", dname_dec(encoded, len, ""), len);
     245    return 0;
     246}
     247#endif
  • branches/2.2.9/mindi-busybox/networking/udhcp/dumpleases.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
     3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
    44 */
    5 #include <getopt.h>
    6 
    75#include "common.h"
    86#include "dhcpd.h"
     7#include "unicode.h"
    98
    10 int dumpleases_main(int argc, char **argv);
    11 int dumpleases_main(int argc, char **argv)
     9int dumpleases_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     10int dumpleases_main(int argc UNUSED_PARAM, char **argv)
    1211{
    1312    int fd;
    1413    int i;
    1514    unsigned opt;
    16     time_t expires;
     15    int64_t written_at, curr, expires_abs;
    1716    const char *file = LEASES_FILE;
    18     struct dhcpOfferedAddr lease;
     17    struct dyn_lease lease;
    1918    struct in_addr addr;
    2019
    2120    enum {
    22         OPT_a   = 0x1,  // -a
    23         OPT_r   = 0x2,  // -r
    24         OPT_f   = 0x4,  // -f
     21        OPT_a = 0x1, // -a
     22        OPT_r = 0x2, // -r
     23        OPT_f = 0x4, // -f
    2524    };
    26 #if ENABLE_GETOPT_LONG
     25#if ENABLE_LONG_OPTS
    2726    static const char dumpleases_longopts[] ALIGN1 =
    2827        "absolute\0"  No_argument       "a"
     
    3332    applet_long_options = dumpleases_longopts;
    3433#endif
     34    init_unicode();
     35
    3536    opt_complementary = "=0:a--r:r--a";
    3637    opt = getopt32(argv, "arf:", &file);
     
    3839    fd = xopen(file, O_RDONLY);
    3940
    40     printf("Mac Address       IP-Address      Expires %s\n", (opt & OPT_a) ? "at" : "in");
    41     /*     "00:00:00:00:00:00 255.255.255.255 Wed Jun 30 21:49:08 1993" */
     41    printf("Mac Address       IP Address      Host Name           Expires %s\n", (opt & OPT_a) ? "at" : "in");
     42    /*     "00:00:00:00:00:00 255.255.255.255 ABCDEFGHIJKLMNOPQRS Wed Jun 30 21:49:08 1993" */
     43    /*     "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */
     44
     45    xread(fd, &written_at, sizeof(written_at));
     46    written_at = SWAP_BE64(written_at);
     47    curr = time(NULL);
     48    if (curr < written_at)
     49        written_at = curr; /* lease file from future! :) */
     50
    4251    while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
    43         printf(":%02x"+1, lease.chaddr[0]);
    44         for (i = 1; i < 6; i++) {
    45             printf(":%02x", lease.chaddr[i]);
     52        const char *fmt = ":%02x" + 1;
     53        for (i = 0; i < 6; i++) {
     54            printf(fmt, lease.lease_mac[i]);
     55            fmt = ":%02x";
    4656        }
    47         addr.s_addr = lease.yiaddr;
    48         printf(" %-15s ", inet_ntoa(addr));
    49         expires = ntohl(lease.expires);
     57        addr.s_addr = lease.lease_nip;
     58#if ENABLE_UNICODE_SUPPORT
     59        {
     60            char *uni_name = unicode_conv_to_printable_fixedwidth(NULL, lease.hostname, 19);
     61            printf(" %-16s%s ", inet_ntoa(addr), uni_name);
     62            free(uni_name);
     63        }
     64#else
     65        /* actually, 15+1 and 19+1, +1 is a space between columns */
     66        /* lease.hostname is char[20] and is always NUL terminated */
     67        printf(" %-16s%-20s", inet_ntoa(addr), lease.hostname);
     68#endif
     69        expires_abs = ntohl(lease.expires) + written_at;
     70        if (expires_abs <= curr) {
     71            puts("expired");
     72            continue;
     73        }
    5074        if (!(opt & OPT_a)) { /* no -a */
    51             if (!expires)
    52                 puts("expired");
    53             else {
    54                 unsigned d, h, m;
    55                 d = expires / (24*60*60); expires %= (24*60*60);
    56                 h = expires / (60*60); expires %= (60*60);
    57                 m = expires / 60; expires %= 60;
    58                 if (d) printf("%u days ", d);
    59                 printf("%02u:%02u:%02u\n", h, m, (unsigned)expires);
    60             }
    61         } else /* -a */
    62             fputs(ctime(&expires), stdout);
     75            unsigned d, h, m;
     76            unsigned expires = expires_abs - curr;
     77            d = expires / (24*60*60); expires %= (24*60*60);
     78            h = expires / (60*60); expires %= (60*60);
     79            m = expires / 60; expires %= 60;
     80            if (d)
     81                printf("%u days ", d);
     82            printf("%02u:%02u:%02u\n", h, m, (unsigned)expires);
     83        } else { /* -a */
     84            time_t t = expires_abs;
     85            fputs(ctime(&t), stdout);
     86        }
    6387    }
    6488    /* close(fd); */
  • branches/2.2.9/mindi-busybox/networking/udhcp/files.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * files.c -- DHCP server file manipulation *
     3 * DHCP server config and lease file manipulation
     4 *
    45 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
     6 *
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    58 */
    6 
    79#include <netinet/ether.h>
    810
    911#include "common.h"
    1012#include "dhcpd.h"
    11 #include "options.h"
    12 
    1313
    1414/* on these functions, make sure your datatype matches */
    15 static int read_ip(const char *line, void *arg)
    16 {
    17     len_and_sockaddr *lsa;
    18 
    19     lsa = host_and_af2sockaddr(line, 0, AF_INET);
    20     if (!lsa)
    21         return 0;
    22     *(uint32_t*)arg = lsa->sin.sin_addr.s_addr;
    23     free(lsa);
    24     return 1;
    25 }
    26 
    27 static int read_mac(const char *line, void *arg)
    28 {
    29     uint8_t *mac_bytes = arg;
    30     struct ether_addr *temp_ether_addr;
    31 
    32     temp_ether_addr = ether_aton(line);
    33     if (temp_ether_addr == NULL)
    34         return 0;
    35     memcpy(mac_bytes, temp_ether_addr, 6);
    36     return 1;
    37 }
    38 
    39 
    40 static int read_str(const char *line, void *arg)
     15static int FAST_FUNC read_str(const char *line, void *arg)
    4116{
    4217    char **dest = arg;
     
    4722}
    4823
    49 
    50 static int read_u32(const char *line, void *arg)
     24static int FAST_FUNC read_u32(const char *line, void *arg)
    5125{
    5226    *(uint32_t*)arg = bb_strtou32(line, NULL, 10);
     
    5428}
    5529
    56 
    57 static int read_yn(const char *line, void *arg)
    58 {
    59     char *dest = arg;
    60 
    61     if (!strcasecmp("yes", line)) {
    62         *dest = 1;
    63         return 1;
    64     }
    65     if (!strcasecmp("no", line)) {
    66         *dest = 0;
    67         return 1;
    68     }
    69     return 0;
    70 }
    71 
    72 
    73 /* find option 'code' in opt_list */
    74 struct option_set *find_option(struct option_set *opt_list, char code)
    75 {
    76     while (opt_list && opt_list->data[OPT_CODE] < code)
    77         opt_list = opt_list->next;
    78 
    79     if (opt_list && opt_list->data[OPT_CODE] == code)
    80         return opt_list;
    81     return NULL;
    82 }
    83 
    84 
    85 /* add an option to the opt_list */
    86 static void attach_option(struct option_set **opt_list,
    87         const struct dhcp_option *option, char *buffer, int length)
    88 {
    89     struct option_set *existing, *new, **curr;
    90 
    91     existing = find_option(*opt_list, option->code);
    92     if (!existing) {
    93         DEBUG("Attaching option %s to list", option->name);
    94 
    95 #if ENABLE_FEATURE_RFC3397
    96         if ((option->flags & TYPE_MASK) == OPTION_STR1035)
    97             /* reuse buffer and length for RFC1035-formatted string */
    98             buffer = dname_enc(NULL, 0, buffer, &length);
    99 #endif
    100 
    101         /* make a new option */
    102         new = xmalloc(sizeof(*new));
    103         new->data = xmalloc(length + 2);
    104         new->data[OPT_CODE] = option->code;
    105         new->data[OPT_LEN] = length;
    106         memcpy(new->data + 2, buffer, length);
    107 
    108         curr = opt_list;
    109         while (*curr && (*curr)->data[OPT_CODE] < option->code)
    110             curr = &(*curr)->next;
    111 
    112         new->next = *curr;
    113         *curr = new;
    114 #if ENABLE_FEATURE_RFC3397
    115         if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL)
    116             free(buffer);
    117 #endif
    118         return;
    119     }
    120 
    121     /* add it to an existing option */
    122     DEBUG("Attaching option %s to existing member of list", option->name);
    123     if (option->flags & OPTION_LIST) {
    124 #if ENABLE_FEATURE_RFC3397
    125         if ((option->flags & TYPE_MASK) == OPTION_STR1035)
    126             /* reuse buffer and length for RFC1035-formatted string */
    127             buffer = dname_enc(existing->data + 2,
    128                     existing->data[OPT_LEN], buffer, &length);
    129 #endif
    130         if (existing->data[OPT_LEN] + length <= 255) {
    131             existing->data = xrealloc(existing->data,
    132                     existing->data[OPT_LEN] + length + 3);
    133             if ((option->flags & TYPE_MASK) == OPTION_STRING) {
    134                 /* ' ' can bring us to 256 - bad */
    135                 if (existing->data[OPT_LEN] + length >= 255)
    136                     return;
    137                 /* add space separator between STRING options in a list */
    138                 existing->data[existing->data[OPT_LEN] + 2] = ' ';
    139                 existing->data[OPT_LEN]++;
    140             }
    141             memcpy(existing->data + existing->data[OPT_LEN] + 2, buffer, length);
    142             existing->data[OPT_LEN] += length;
    143         } /* else, ignore the data, we could put this in a second option in the future */
    144 #if ENABLE_FEATURE_RFC3397
    145         if ((option->flags & TYPE_MASK) == OPTION_STR1035 && buffer != NULL)
    146             free(buffer);
    147 #endif
    148     } /* else, ignore the new data */
    149 }
    150 
    151 
    152 /* read a dhcp option and add it to opt_list */
    153 static int read_opt(const char *const_line, void *arg)
    154 {
    155     struct option_set **opt_list = arg;
    156     char *opt, *val, *endptr;
    157     const struct dhcp_option *option;
    158     int retval = 0, length;
    159     char buffer[8];
    160     char *line;
    161     uint16_t *result_u16 = (uint16_t *) buffer;
    162     uint32_t *result_u32 = (uint32_t *) buffer;
    163 
    164     /* Cheat, the only const line we'll actually get is "" */
    165     line = (char *) const_line;
    166     opt = strtok(line, " \t=");
    167     if (!opt) return 0;
    168 
    169     option = dhcp_options;
    170     while (1) {
    171         if (!option->code)
    172             return 0;
    173         if (!strcasecmp(option->name, opt))
    174             break;
    175         option++;
    176     }
    177 
    178     do {
    179         val = strtok(NULL, ", \t");
    180         if (!val) break;
    181         length = option_lengths[option->flags & TYPE_MASK];
    182         retval = 0;
    183         opt = buffer; /* new meaning for variable opt */
    184         switch (option->flags & TYPE_MASK) {
    185         case OPTION_IP:
    186             retval = read_ip(val, buffer);
    187             break;
    188         case OPTION_IP_PAIR:
    189             retval = read_ip(val, buffer);
    190             val = strtok(NULL, ", \t/-");
    191             if (!val)
    192                 retval = 0;
    193             if (retval)
    194                 retval = read_ip(val, buffer + 4);
    195             break;
    196         case OPTION_STRING:
    197 #if ENABLE_FEATURE_RFC3397
    198         case OPTION_STR1035:
    199 #endif
    200             length = strlen(val);
    201             if (length > 0) {
    202                 if (length > 254) length = 254;
    203                 opt = val;
    204                 retval = 1;
    205             }
    206             break;
    207         case OPTION_BOOLEAN:
    208             retval = read_yn(val, buffer);
    209             break;
    210         case OPTION_U8:
    211             buffer[0] = strtoul(val, &endptr, 0);
    212             retval = (endptr[0] == '\0');
    213             break;
    214         /* htonX are macros in older libc's, using temp var
    215          * in code below for safety */
    216         /* TODO: use bb_strtoX? */
    217         case OPTION_U16: {
    218             unsigned long tmp = strtoul(val, &endptr, 0);
    219             *result_u16 = htons(tmp);
    220             retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/);
    221             break;
    222         }
    223         case OPTION_S16: {
    224             long tmp = strtol(val, &endptr, 0);
    225             *result_u16 = htons(tmp);
    226             retval = (endptr[0] == '\0');
    227             break;
    228         }
    229         case OPTION_U32: {
    230             unsigned long tmp = strtoul(val, &endptr, 0);
    231             *result_u32 = htonl(tmp);
    232             retval = (endptr[0] == '\0');
    233             break;
    234         }
    235         case OPTION_S32: {
    236             long tmp = strtol(val, &endptr, 0);
    237             *result_u32 = htonl(tmp);
    238             retval = (endptr[0] == '\0');
    239             break;
    240         }
    241         default:
    242             break;
    243         }
    244         if (retval)
    245             attach_option(opt_list, option, opt, length);
    246     } while (retval && option->flags & OPTION_LIST);
    247     return retval;
    248 }
    249 
    250 static int read_staticlease(const char *const_line, void *arg)
     30static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
    25131{
    25232    char *line;
    25333    char *mac_string;
    25434    char *ip_string;
    255     uint8_t *mac_bytes;
    256     uint32_t *ip;
    257 
    258     /* Allocate memory for addresses */
    259     mac_bytes = xmalloc(sizeof(unsigned char) * 8);
    260     ip = xmalloc(sizeof(uint32_t));
     35    struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */
     36    uint32_t nip;
    26137
    26238    /* Read mac */
    26339    line = (char *) const_line;
    264     mac_string = strtok(line, " \t");
    265     read_mac(mac_string, mac_bytes);
     40    mac_string = strtok_r(line, " \t", &line);
     41    if (!mac_string || !ether_aton_r(mac_string, &mac_bytes))
     42        return 0;
    26643
    26744    /* Read ip */
    268     ip_string = strtok(NULL, " \t");
    269     read_ip(ip_string, ip);
    270 
    271     addStaticLease(arg, mac_bytes, ip);
    272 
    273     if (ENABLE_FEATURE_UDHCP_DEBUG) printStaticLeases(arg);
     45    ip_string = strtok_r(NULL, " \t", &line);
     46    if (!ip_string || !udhcp_str2nip(ip_string, &nip))
     47        return 0;
     48
     49    add_static_lease(arg, (uint8_t*) &mac_bytes, nip);
     50
     51    log_static_leases(arg);
    27452
    27553    return 1;
     
    27957struct config_keyword {
    28058    const char *keyword;
    281     int (*handler)(const char *line, void *var);
     59    int (*handler)(const char *line, void *var) FAST_FUNC;
    28260    void *var;
    28361    const char *def;
     
    28563
    28664static const struct config_keyword keywords[] = {
    287     /* keyword       handler   variable address               default */
    288     {"start",        read_ip,  &(server_config.start_ip),     "192.168.0.20"},
    289     {"end",          read_ip,  &(server_config.end_ip),       "192.168.0.254"},
    290     {"interface",    read_str, &(server_config.interface),    "eth0"},
    291     {"option",       read_opt, &(server_config.options),      ""},
    292     {"opt",          read_opt, &(server_config.options),      ""},
     65    /* keyword        handler           variable address               default */
     66    {"start"        , udhcp_str2nip   , &server_config.start_ip     , "192.168.0.20"},
     67    {"end"          , udhcp_str2nip   , &server_config.end_ip       , "192.168.0.254"},
     68    {"interface"    , read_str        , &server_config.interface    , "eth0"},
    29369    /* Avoid "max_leases value not sane" warning by setting default
    29470     * to default_end_ip - default_start_ip + 1: */
    295     {"max_leases",   read_u32, &(server_config.max_leases),   "235"},
    296     {"remaining",    read_yn,  &(server_config.remaining),    "yes"},
    297     {"auto_time",    read_u32, &(server_config.auto_time),    "7200"},
    298     {"decline_time", read_u32, &(server_config.decline_time), "3600"},
    299     {"conflict_time",read_u32, &(server_config.conflict_time),"3600"},
    300     {"offer_time",   read_u32, &(server_config.offer_time),   "60"},
    301     {"min_lease",    read_u32, &(server_config.min_lease),    "60"},
    302     {"lease_file",   read_str, &(server_config.lease_file),   LEASES_FILE},
    303     {"pidfile",      read_str, &(server_config.pidfile),      "/var/run/udhcpd.pid"},
    304     {"notify_file",  read_str, &(server_config.notify_file),  ""},
    305     {"siaddr",       read_ip,  &(server_config.siaddr),       "0.0.0.0"},
    306     {"sname",        read_str, &(server_config.sname),        ""},
    307     {"boot_file",    read_str, &(server_config.boot_file),    ""},
    308     {"static_lease", read_staticlease, &(server_config.static_leases), ""},
    309     /* ADDME: static lease */
     71    {"max_leases"   , read_u32        , &server_config.max_leases   , "235"},
     72    {"auto_time"    , read_u32        , &server_config.auto_time    , "7200"},
     73    {"decline_time" , read_u32        , &server_config.decline_time , "3600"},
     74    {"conflict_time", read_u32        , &server_config.conflict_time, "3600"},
     75    {"offer_time"   , read_u32        , &server_config.offer_time   , "60"},
     76    {"min_lease"    , read_u32        , &server_config.min_lease_sec, "60"},
     77    {"lease_file"   , read_str        , &server_config.lease_file   , LEASES_FILE},
     78    {"pidfile"      , read_str        , &server_config.pidfile      , "/var/run/udhcpd.pid"},
     79    {"siaddr"       , udhcp_str2nip   , &server_config.siaddr_nip   , "0.0.0.0"},
     80    /* keywords with no defaults must be last! */
     81    {"option"       , udhcp_str2optset, &server_config.options      , ""},
     82    {"opt"          , udhcp_str2optset, &server_config.options      , ""},
     83    {"notify_file"  , read_str        , &server_config.notify_file  , ""},
     84    {"sname"        , read_str        , &server_config.sname        , ""},
     85    {"boot_file"    , read_str        , &server_config.boot_file    , ""},
     86    {"static_lease" , read_staticlease, &server_config.static_leases, ""},
    31087};
    311 
    312 
    313 /*
    314  * Domain names may have 254 chars, and string options can be 254
    315  * chars long. However, 80 bytes will be enough for most, and won't
    316  * hog up memory. If you have a special application, change it
    317  */
    318 #define READ_CONFIG_BUF_SIZE 80
    319 
    320 int read_config(const char *file)
    321 {
    322     FILE *in;
    323     char buffer[READ_CONFIG_BUF_SIZE], *token, *line;
    324     int i, lm = 0;
    325 
    326     for (i = 0; i < ARRAY_SIZE(keywords); i++)
    327         if (keywords[i].def[0])
    328             keywords[i].handler(keywords[i].def, keywords[i].var);
    329 
    330     in = fopen_or_warn(file, "r");
    331     if (!in) {
    332         return 0;
    333     }
    334 
    335     while (fgets(buffer, READ_CONFIG_BUF_SIZE, in)) {
    336         char debug_orig[READ_CONFIG_BUF_SIZE];
    337         char *p;
    338 
    339         lm++;
    340         p = strchr(buffer, '\n');
    341         if (p) *p = '\0';
    342         if (ENABLE_FEATURE_UDHCP_DEBUG) strcpy(debug_orig, buffer);
    343         p = strchr(buffer, '#');
    344         if (p) *p = '\0';
    345 
    346         if (!(token = strtok(buffer, " \t"))) continue;
    347         if (!(line = strtok(NULL, ""))) continue;
    348 
    349         /* eat leading whitespace */
    350         line = skip_whitespace(line);
    351         /* eat trailing whitespace */
    352         i = strlen(line) - 1;
    353         while (i >= 0 && isspace(line[i]))
    354             line[i--] = '\0';
    355 
    356         for (i = 0; i < ARRAY_SIZE(keywords); i++)
    357             if (!strcasecmp(token, keywords[i].keyword))
    358                 if (!keywords[i].handler(line, keywords[i].var)) {
    359                     bb_error_msg("cannot parse line %d of %s", lm, file);
    360                     if (ENABLE_FEATURE_UDHCP_DEBUG)
    361                         bb_error_msg("cannot parse '%s'", debug_orig);
     88enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
     89
     90void FAST_FUNC read_config(const char *file)
     91{
     92    parser_t *parser;
     93    const struct config_keyword *k;
     94    unsigned i;
     95    char *token[2];
     96
     97    for (i = 0; i < KWS_WITH_DEFAULTS; i++)
     98        keywords[i].handler(keywords[i].def, keywords[i].var);
     99
     100    parser = config_open(file);
     101    while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
     102        for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
     103            if (strcasecmp(token[0], k->keyword) == 0) {
     104                if (!k->handler(token[1], k->var)) {
     105                    bb_error_msg("can't parse line %u in %s",
     106                            parser->lineno, file);
    362107                    /* reset back to the default value */
    363                     keywords[i].handler(keywords[i].def, keywords[i].var);
     108                    k->handler(k->def, k->var);
    364109                }
    365     }
    366     fclose(in);
     110                break;
     111            }
     112        }
     113    }
     114    config_close(parser);
    367115
    368116    server_config.start_ip = ntohl(server_config.start_ip);
    369117    server_config.end_ip = ntohl(server_config.end_ip);
    370 
    371     return 1;
    372 }
    373 
    374 
    375 void write_leases(void)
    376 {
    377     int fp;
     118}
     119
     120void FAST_FUNC write_leases(void)
     121{
     122    int fd;
    378123    unsigned i;
    379     time_t curr = time(0);
    380     unsigned long tmp_time;
    381 
    382     fp = open3_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC, 0666);
    383     if (fp < 0) {
     124    leasetime_t curr;
     125    int64_t written_at;
     126
     127    fd = open_or_warn(server_config.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
     128    if (fd < 0)
    384129        return;
    385     }
     130
     131    curr = written_at = time(NULL);
     132
     133    written_at = SWAP_BE64(written_at);
     134    full_write(fd, &written_at, sizeof(written_at));
    386135
    387136    for (i = 0; i < server_config.max_leases; i++) {
    388         if (leases[i].yiaddr != 0) {
    389 
    390             /* screw with the time in the struct, for easier writing */
    391             tmp_time = leases[i].expires;
    392 
    393             if (server_config.remaining) {
    394                 if (lease_expired(&(leases[i])))
    395                     leases[i].expires = 0;
    396                 else leases[i].expires -= curr;
    397             } /* else stick with the time we got */
    398             leases[i].expires = htonl(leases[i].expires);
    399             // FIXME: error check??
    400             full_write(fp, &leases[i], sizeof(leases[i]));
    401 
    402             /* then restore it when done */
    403             leases[i].expires = tmp_time;
    404         }
    405     }
    406     close(fp);
     137        leasetime_t tmp_time;
     138
     139        if (g_leases[i].lease_nip == 0)
     140            continue;
     141
     142        /* Screw with the time in the struct, for easier writing */
     143        tmp_time = g_leases[i].expires;
     144
     145        g_leases[i].expires -= curr;
     146        if ((signed_leasetime_t) g_leases[i].expires < 0)
     147            g_leases[i].expires = 0;
     148        g_leases[i].expires = htonl(g_leases[i].expires);
     149
     150        /* No error check. If the file gets truncated,
     151         * we lose some leases on restart. Oh well. */
     152        full_write(fd, &g_leases[i], sizeof(g_leases[i]));
     153
     154        /* Then restore it when done */
     155        g_leases[i].expires = tmp_time;
     156    }
     157    close(fd);
    407158
    408159    if (server_config.notify_file) {
    409         char *cmd = xasprintf("%s %s", server_config.notify_file, server_config.lease_file);
    410         system(cmd);
    411         free(cmd);
    412     }
    413 }
    414 
    415 
    416 void read_leases(const char *file)
    417 {
    418     int fp;
    419     unsigned int i = 0;
    420     struct dhcpOfferedAddr lease;
    421 
    422     fp = open_or_warn(file, O_RDONLY);
    423     if (fp < 0) {
     160        char *argv[3];
     161        argv[0] = server_config.notify_file;
     162        argv[1] = server_config.lease_file;
     163        argv[2] = NULL;
     164        spawn_and_wait(argv);
     165    }
     166}
     167
     168void FAST_FUNC read_leases(const char *file)
     169{
     170    struct dyn_lease lease;
     171    int64_t written_at, time_passed;
     172    int fd;
     173#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
     174    unsigned i = 0;
     175#endif
     176
     177    fd = open_or_warn(file, O_RDONLY);
     178    if (fd < 0)
    424179        return;
    425     }
    426 
    427     while (i < server_config.max_leases
    428      && full_read(fp, &lease, sizeof(lease)) == sizeof(lease)
    429     ) {
    430         /* ADDME: is it a static lease */
    431         uint32_t y = ntohl(lease.yiaddr);
     180
     181    if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
     182        goto ret;
     183    written_at = SWAP_BE64(written_at);
     184
     185    time_passed = time(NULL) - written_at;
     186    /* Strange written_at, or lease file from old version of udhcpd
     187     * which had no "written_at" field? */
     188    if ((uint64_t)time_passed > 12 * 60 * 60)
     189        goto ret;
     190
     191    while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
     192//FIXME: what if it matches some static lease?
     193        uint32_t y = ntohl(lease.lease_nip);
    432194        if (y >= server_config.start_ip && y <= server_config.end_ip) {
    433             lease.expires = ntohl(lease.expires);
    434             if (!server_config.remaining)
    435                 lease.expires -= time(0);
    436             if (!(add_lease(lease.chaddr, lease.yiaddr, lease.expires))) {
     195            signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed;
     196            if (expires <= 0)
     197                continue;
     198            /* NB: add_lease takes "relative time", IOW,
     199             * lease duration, not lease deadline. */
     200            if (add_lease(lease.lease_mac, lease.lease_nip,
     201                    expires,
     202                    lease.hostname, sizeof(lease.hostname)
     203                ) == 0
     204            ) {
    437205                bb_error_msg("too many leases while loading %s", file);
    438206                break;
    439207            }
     208#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
    440209            i++;
     210#endif
    441211        }
    442212    }
    443     DEBUG("Read %d leases", i);
    444     close(fp);
    445 }
     213    log1("Read %d leases", i);
     214 ret:
     215    close(fd);
     216}
  • branches/2.2.9/mindi-busybox/networking/udhcp/leases.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * leases.c -- tools to manage DHCP leases
    43 * Russ Dill <Russ.Dill@asu.edu> July 2001
     4 *
     5 * Licensed under GPLv2, see file LICENSE in this source tree.
    56 */
    6 
    77#include "common.h"
    88#include "dhcpd.h"
    99
    10 
    1110/* Find the oldest expired lease, NULL if there are no expired leases */
    12 static struct dhcpOfferedAddr *oldest_expired_lease(void)
     11static struct dyn_lease *oldest_expired_lease(void)
    1312{
    14     struct dhcpOfferedAddr *oldest = NULL;
    15 // TODO: use monotonic_sec()
    16     unsigned long oldest_lease = time(0);
     13    struct dyn_lease *oldest_lease = NULL;
     14    leasetime_t oldest_time = time(NULL);
    1715    unsigned i;
    1816
    19     for (i = 0; i < server_config.max_leases; i++)
    20         if (oldest_lease > leases[i].expires) {
    21             oldest_lease = leases[i].expires;
    22             oldest = &(leases[i]);
     17    /* Unexpired leases have g_leases[i].expires >= current time
     18     * and therefore can't ever match */
     19    for (i = 0; i < server_config.max_leases; i++) {
     20        if (g_leases[i].expires < oldest_time) {
     21            oldest_time = g_leases[i].expires;
     22            oldest_lease = &g_leases[i];
    2323        }
    24     return oldest;
     24    }
     25    return oldest_lease;
    2526}
    2627
     28/* Clear out all leases with matching nonzero chaddr OR yiaddr.
     29 * If chaddr == NULL, this is a conflict lease.
     30 */
     31static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr)
     32{
     33    unsigned i;
    2734
    28 /* clear every lease out that chaddr OR yiaddr matches and is nonzero */
    29 static void clear_lease(const uint8_t *chaddr, uint32_t yiaddr)
    30 {
    31     unsigned i, j;
    32 
    33     for (j = 0; j < 16 && !chaddr[j]; j++)
    34         continue;
    35 
    36     for (i = 0; i < server_config.max_leases; i++)
    37         if ((j != 16 && memcmp(leases[i].chaddr, chaddr, 16) == 0)
    38          || (yiaddr && leases[i].yiaddr == yiaddr)
     35    for (i = 0; i < server_config.max_leases; i++) {
     36        if ((chaddr && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0)
     37         || (yiaddr && g_leases[i].lease_nip == yiaddr)
    3938        ) {
    40             memset(&(leases[i]), 0, sizeof(leases[i]));
     39            memset(&g_leases[i], 0, sizeof(g_leases[i]));
    4140        }
     41    }
    4242}
    4343
    44 
    45 /* add a lease into the table, clearing out any old ones */
    46 struct dhcpOfferedAddr *add_lease(const uint8_t *chaddr, uint32_t yiaddr, unsigned long lease)
     44/* Add a lease into the table, clearing out any old ones.
     45 * If chaddr == NULL, this is a conflict lease.
     46 */
     47struct dyn_lease* FAST_FUNC add_lease(
     48        const uint8_t *chaddr, uint32_t yiaddr,
     49        leasetime_t leasetime,
     50        const char *hostname, int hostname_len)
    4751{
    48     struct dhcpOfferedAddr *oldest;
     52    struct dyn_lease *oldest;
    4953
    5054    /* clean out any old ones */
    51     clear_lease(chaddr, yiaddr);
     55    clear_leases(chaddr, yiaddr);
    5256
    5357    oldest = oldest_expired_lease();
    5458
    5559    if (oldest) {
    56         memcpy(oldest->chaddr, chaddr, 16);
    57         oldest->yiaddr = yiaddr;
    58         oldest->expires = time(0) + lease;
     60        memset(oldest, 0, sizeof(*oldest));
     61        if (hostname) {
     62            char *p;
     63
     64            hostname_len++; /* include NUL */
     65            if (hostname_len > sizeof(oldest->hostname))
     66                hostname_len = sizeof(oldest->hostname);
     67            p = safe_strncpy(oldest->hostname, hostname, hostname_len);
     68            /* sanitization (s/non-ASCII/^/g) */
     69            while (*p) {
     70                if (*p < ' ' || *p > 126)
     71                    *p = '^';
     72                p++;
     73            }
     74        }
     75        if (chaddr)
     76            memcpy(oldest->lease_mac, chaddr, 6);
     77        oldest->lease_nip = yiaddr;
     78        oldest->expires = time(NULL) + leasetime;
    5979    }
    6080
     
    6282}
    6383
    64 
    65 /* true if a lease has expired */
    66 int lease_expired(struct dhcpOfferedAddr *lease)
     84/* True if a lease has expired */
     85int FAST_FUNC is_expired_lease(struct dyn_lease *lease)
    6786{
    68     return (lease->expires < (unsigned long) time(0));
     87    return (lease->expires < (leasetime_t) time(NULL));
    6988}
    7089
    71 
    72 /* Find the first lease that matches chaddr, NULL if no match */
    73 struct dhcpOfferedAddr *find_lease_by_chaddr(const uint8_t *chaddr)
     90/* Find the first lease that matches MAC, NULL if no match */
     91struct dyn_lease* FAST_FUNC find_lease_by_mac(const uint8_t *mac)
    7492{
    7593    unsigned i;
    7694
    7795    for (i = 0; i < server_config.max_leases; i++)
    78         if (!memcmp(leases[i].chaddr, chaddr, 16))
    79             return &(leases[i]);
     96        if (memcmp(g_leases[i].lease_mac, mac, 6) == 0)
     97            return &g_leases[i];
    8098
    8199    return NULL;
    82100}
    83101
    84 
    85 /* Find the first lease that matches yiaddr, NULL is no match */
    86 struct dhcpOfferedAddr *find_lease_by_yiaddr(uint32_t yiaddr)
     102/* Find the first lease that matches IP, NULL is no match */
     103struct dyn_lease* FAST_FUNC find_lease_by_nip(uint32_t nip)
    87104{
    88105    unsigned i;
    89106
    90107    for (i = 0; i < server_config.max_leases; i++)
    91         if (leases[i].yiaddr == yiaddr)
    92             return &(leases[i]);
     108        if (g_leases[i].lease_nip == nip)
     109            return &g_leases[i];
    93110
    94111    return NULL;
    95112}
    96113
    97 
    98 /* check is an IP is taken, if it is, add it to the lease table */
    99 static int nobody_responds_to_arp(uint32_t addr)
     114/* Check if the IP is taken; if it is, add it to the lease table */
     115static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac)
    100116{
    101     static const uint8_t blank_chaddr[16]; /* 16 zero bytes */
    102 
    103117    struct in_addr temp;
    104118    int r;
    105119
    106     r = arpping(addr, server_config.server, server_config.arp, server_config.interface);
     120    r = arpping(nip, safe_mac,
     121            server_config.server_nip,
     122            server_config.server_mac,
     123            server_config.interface);
    107124    if (r)
    108125        return r;
    109126
    110     temp.s_addr = addr;
     127    temp.s_addr = nip;
    111128    bb_info_msg("%s belongs to someone, reserving it for %u seconds",
    112129        inet_ntoa(temp), (unsigned)server_config.conflict_time);
    113     add_lease(blank_chaddr, addr, server_config.conflict_time);
     130    add_lease(NULL, nip, server_config.conflict_time, NULL, 0);
    114131    return 0;
    115132}
    116133
    117 
    118 /* find an assignable address, if check_expired is true, we check all the expired leases as well.
    119  * Maybe this should try expired leases by age... */
    120 uint32_t find_address(int check_expired)
     134/* Find a new usable (we think) address */
     135uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac)
    121136{
    122     uint32_t addr, ret;
    123     struct dhcpOfferedAddr *lease = NULL;
     137    uint32_t addr;
     138    struct dyn_lease *oldest_lease = NULL;
    124139
    125140    addr = server_config.start_ip; /* addr is in host order here */
    126141    for (; addr <= server_config.end_ip; addr++) {
     142        uint32_t nip;
     143        struct dyn_lease *lease;
     144
    127145        /* ie, 192.168.55.0 */
    128         if (!(addr & 0xFF))
     146        if ((addr & 0xff) == 0)
    129147            continue;
    130148        /* ie, 192.168.55.255 */
    131         if ((addr & 0xFF) == 0xFF)
     149        if ((addr & 0xff) == 0xff)
    132150            continue;
    133         /* Only do if it isn't assigned as a static lease */
    134         ret = htonl(addr);
    135         if (!reservedIp(server_config.static_leases, ret)) {
    136             /* lease is not taken */
    137             lease = find_lease_by_yiaddr(ret);
    138             /* no lease or it expired and we are checking for expired leases */
    139             if ((!lease || (check_expired && lease_expired(lease)))
    140              && nobody_responds_to_arp(ret) /* it isn't used on the network */
    141             ) {
    142                 return ret;
    143             }
     151        nip = htonl(addr);
     152        /* is this a static lease addr? */
     153        if (is_nip_reserved(server_config.static_leases, nip))
     154            continue;
     155
     156        lease = find_lease_by_nip(nip);
     157        if (!lease) {
     158//TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping!
     159            if (nobody_responds_to_arp(nip, safe_mac))
     160                return nip;
     161        } else {
     162            if (!oldest_lease || lease->expires < oldest_lease->expires)
     163                oldest_lease = lease;
    144164        }
    145165    }
     166
     167    if (oldest_lease
     168     && is_expired_lease(oldest_lease)
     169     && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac)
     170    ) {
     171        return oldest_lease->lease_nip;
     172    }
     173
    146174    return 0;
    147175}
  • branches/2.2.9/mindi-busybox/networking/udhcp/packet.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 
     2/*
     3 * Packet ops
     4 *
     5 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
     6 *
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
     8 */
    39#include <netinet/in.h>
    410#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
    5 #include <netpacket/packet.h>
    6 #include <net/ethernet.h>
     11# include <netpacket/packet.h>
     12# include <net/ethernet.h>
    713#else
    8 #include <asm/types.h>
    9 #include <linux/if_packet.h>
    10 #include <linux/if_ether.h>
     14# include <asm/types.h>
     15# include <linux/if_packet.h>
     16# include <linux/if_ether.h>
    1117#endif
    1218
    1319#include "common.h"
    1420#include "dhcpd.h"
    15 #include "options.h"
    16 
    17 
    18 void udhcp_init_header(struct dhcpMessage *packet, char type)
    19 {
    20     memset(packet, 0, sizeof(struct dhcpMessage));
     21
     22void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type)
     23{
     24    memset(packet, 0, sizeof(*packet));
     25    packet->op = BOOTREQUEST; /* if client to a server */
    2126    switch (type) {
    22     case DHCPDISCOVER:
    23     case DHCPREQUEST:
    24     case DHCPRELEASE:
    25     case DHCPINFORM:
    26         packet->op = BOOTREQUEST;
    27         break;
    2827    case DHCPOFFER:
    2928    case DHCPACK:
    3029    case DHCPNAK:
    31         packet->op = BOOTREPLY;
    32     }
    33     packet->htype = ETH_10MB;
    34     packet->hlen = ETH_10MB_LEN;
     30        packet->op = BOOTREPLY; /* if server to client */
     31    }
     32    packet->htype = 1; /* ethernet */
     33    packet->hlen = 6;
    3534    packet->cookie = htonl(DHCP_MAGIC);
    36     packet->options[0] = DHCP_END;
    37     add_simple_option(packet->options, DHCP_MESSAGE_TYPE, type);
    38 }
    39 
    40 
    41 /* read a packet from socket fd, return -1 on read error, -2 on packet error */
    42 int udhcp_get_packet(struct dhcpMessage *packet, int fd)
    43 {
    44 #if 0
    45     static const char broken_vendors[][8] = {
    46         "MSFT 98",
    47         ""
    48     };
     35    if (DHCP_END != 0)
     36        packet->options[0] = DHCP_END;
     37    udhcp_add_simple_option(packet, DHCP_MESSAGE_TYPE, type);
     38}
     39
     40#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
     41void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet)
     42{
     43    char buf[sizeof(packet->chaddr)*2 + 1];
     44
     45    if (dhcp_verbose < 2)
     46        return;
     47
     48    bb_info_msg(
     49        //" op %x"
     50        //" htype %x"
     51        " hlen %x"
     52        //" hops %x"
     53        " xid %x"
     54        //" secs %x"
     55        //" flags %x"
     56        " ciaddr %x"
     57        " yiaddr %x"
     58        " siaddr %x"
     59        " giaddr %x"
     60        //" chaddr %s"
     61        //" sname %s"
     62        //" file %s"
     63        //" cookie %x"
     64        //" options %s"
     65        //, packet->op
     66        //, packet->htype
     67        , packet->hlen
     68        //, packet->hops
     69        , packet->xid
     70        //, packet->secs
     71        //, packet->flags
     72        , packet->ciaddr
     73        , packet->yiaddr
     74        , packet->siaddr_nip
     75        , packet->gateway_nip
     76        //, packet->chaddr[16]
     77        //, packet->sname[64]
     78        //, packet->file[128]
     79        //, packet->cookie
     80        //, packet->options[]
     81    );
     82    *bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0';
     83    bb_info_msg(" chaddr %s", buf);
     84}
    4985#endif
     86
     87/* Read a packet from socket fd, return -1 on read error, -2 on packet error */
     88int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd)
     89{
    5090    int bytes;
    5191    unsigned char *vendor;
    5292
    5393    memset(packet, 0, sizeof(*packet));
    54     bytes = read(fd, packet, sizeof(*packet));
     94    bytes = safe_read(fd, packet, sizeof(*packet));
    5595    if (bytes < 0) {
    56         DEBUG("cannot read on listening socket, ignoring");
    57         return -1;
    58     }
    59 
    60     if (ntohl(packet->cookie) != DHCP_MAGIC) {
    61         bb_error_msg("received bogus message, ignoring");
     96        log1("Packet read error, ignoring");
     97        return bytes; /* returns -1 */
     98    }
     99
     100    if (packet->cookie != htonl(DHCP_MAGIC)) {
     101        bb_info_msg("Packet with bad magic, ignoring");
    62102        return -2;
    63103    }
    64     DEBUG("Received a packet");
     104    log1("Received a packet");
     105    udhcp_dump_packet(packet);
    65106
    66107    if (packet->op == BOOTREQUEST) {
    67         vendor = get_option(packet, DHCP_VENDOR);
     108        vendor = udhcp_get_option(packet, DHCP_VENDOR);
    68109        if (vendor) {
    69110#if 0
     111            static const char broken_vendors[][8] = {
     112                "MSFT 98",
     113                ""
     114            };
    70115            int i;
    71116            for (i = 0; broken_vendors[i][0]; i++) {
    72                 if (vendor[OPT_LEN - 2] == (uint8_t)strlen(broken_vendors[i])
    73                  && !strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - 2])
     117                if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)strlen(broken_vendors[i])
     118                 && strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - OPT_DATA]) == 0
    74119                ) {
    75                     DEBUG("broken client (%s), forcing broadcast",
     120                    log1("Broken client (%s), forcing broadcast replies",
    76121                        broken_vendors[i]);
    77122                    packet->flags |= htons(BROADCAST_FLAG);
     
    79124            }
    80125#else
    81             if (vendor[OPT_LEN - 2] == (uint8_t)(sizeof("MSFT 98")-1)
     126            if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)(sizeof("MSFT 98")-1)
    82127             && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0
    83128            ) {
    84                 DEBUG("broken client (%s), forcing broadcast", "MSFT 98");
     129                log1("Broken client (%s), forcing broadcast replies", "MSFT 98");
    85130                packet->flags |= htons(BROADCAST_FLAG);
    86131            }
     
    92137}
    93138
    94 
    95 uint16_t udhcp_checksum(void *addr, int count)
     139uint16_t FAST_FUNC udhcp_checksum(void *addr, int count)
    96140{
    97141    /* Compute Internet Checksum for "count" bytes
    98      *         beginning at location "addr".
     142     * beginning at location "addr".
    99143     */
    100144    int32_t sum = 0;
     
    112156         * with little and big endian hosts */
    113157        uint16_t tmp = 0;
    114         *(uint8_t *) (&tmp) = * (uint8_t *) source;
     158        *(uint8_t*)&tmp = *(uint8_t*)source;
    115159        sum += tmp;
    116160    }
     
    122166}
    123167
    124 
    125 /* Construct a ip/udp header for a packet, and specify the source and dest hardware address */
    126 void BUG_sizeof_struct_udp_dhcp_packet_must_be_576(void);
    127 int udhcp_raw_packet(struct dhcpMessage *payload,
    128         uint32_t source_ip, int source_port,
    129         uint32_t dest_ip, int dest_port, const uint8_t *dest_arp, int ifindex)
    130 {
     168/* Construct a ip/udp header for a packet, send packet */
     169int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
     170        uint32_t source_nip, int source_port,
     171        uint32_t dest_nip, int dest_port, const uint8_t *dest_arp,
     172        int ifindex)
     173{
     174    struct sockaddr_ll dest_sll;
     175    struct ip_udp_dhcp_packet packet;
     176    unsigned padding;
    131177    int fd;
    132     int result;
    133     struct sockaddr_ll dest;
    134     struct udp_dhcp_packet packet;
     178    int result = -1;
     179    const char *msg;
    135180
    136181    fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
    137182    if (fd < 0) {
    138         bb_perror_msg("socket");
    139         return -1;
    140     }
    141 
    142     memset(&dest, 0, sizeof(dest));
    143     memset(&packet, 0, sizeof(packet));
    144 
    145     dest.sll_family = AF_PACKET;
    146     dest.sll_protocol = htons(ETH_P_IP);
    147     dest.sll_ifindex = ifindex;
    148     dest.sll_halen = 6;
    149     memcpy(dest.sll_addr, dest_arp, 6);
    150     if (bind(fd, (struct sockaddr *)&dest, sizeof(struct sockaddr_ll)) < 0) {
    151         bb_perror_msg("bind");
    152         close(fd);
    153         return -1;
    154     }
     183        msg = "socket(%s)";
     184        goto ret_msg;
     185    }
     186
     187    memset(&dest_sll, 0, sizeof(dest_sll));
     188    memset(&packet, 0, offsetof(struct ip_udp_dhcp_packet, data));
     189    packet.data = *dhcp_pkt; /* struct copy */
     190
     191    dest_sll.sll_family = AF_PACKET;
     192    dest_sll.sll_protocol = htons(ETH_P_IP);
     193    dest_sll.sll_ifindex = ifindex;
     194    dest_sll.sll_halen = 6;
     195    memcpy(dest_sll.sll_addr, dest_arp, 6);
     196
     197    if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) {
     198        msg = "bind(%s)";
     199        goto ret_close;
     200    }
     201
     202    /* We were sending full-sized DHCP packets (zero padded),
     203     * but some badly configured servers were seen dropping them.
     204     * Apparently they drop all DHCP packets >576 *ethernet* octets big,
     205     * whereas they may only drop packets >576 *IP* octets big
     206     * (which for typical Ethernet II means 590 octets: 6+6+2 + 576).
     207     *
     208     * In order to work with those buggy servers,
     209     * we truncate packets after end option byte.
     210     */
     211    padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options);
    155212
    156213    packet.ip.protocol = IPPROTO_UDP;
    157     packet.ip.saddr = source_ip;
    158     packet.ip.daddr = dest_ip;
     214    packet.ip.saddr = source_nip;
     215    packet.ip.daddr = dest_nip;
    159216    packet.udp.source = htons(source_port);
    160217    packet.udp.dest = htons(dest_port);
    161     packet.udp.len = htons(sizeof(packet.udp) + sizeof(struct dhcpMessage)); /* cheat on the psuedo-header */
     218    /* size, excluding IP header: */
     219    packet.udp.len = htons(UDP_DHCP_SIZE - padding);
     220    /* for UDP checksumming, ip.len is set to UDP packet len */
    162221    packet.ip.tot_len = packet.udp.len;
    163     memcpy(&(packet.data), payload, sizeof(struct dhcpMessage));
    164     packet.udp.check = udhcp_checksum(&packet, sizeof(struct udp_dhcp_packet));
    165 
    166     packet.ip.tot_len = htons(sizeof(struct udp_dhcp_packet));
     222    packet.udp.check = udhcp_checksum(&packet, IP_UDP_DHCP_SIZE - padding);
     223    /* but for sending, it is set to IP packet len */
     224    packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding);
    167225    packet.ip.ihl = sizeof(packet.ip) >> 2;
    168226    packet.ip.version = IPVERSION;
    169227    packet.ip.ttl = IPDEFTTL;
    170     packet.ip.check = udhcp_checksum(&(packet.ip), sizeof(packet.ip));
    171 
    172     if (sizeof(struct udp_dhcp_packet) != 576)
    173         BUG_sizeof_struct_udp_dhcp_packet_must_be_576();
    174 
    175     result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0,
    176             (struct sockaddr *) &dest, sizeof(dest));
    177     if (result <= 0) {
    178         bb_perror_msg("sendto");
    179     }
     228    packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip));
     229
     230    udhcp_dump_packet(dhcp_pkt);
     231    result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0,
     232            (struct sockaddr *) &dest_sll, sizeof(dest_sll));
     233    msg = "sendto";
     234 ret_close:
    180235    close(fd);
     236    if (result < 0) {
     237 ret_msg:
     238        bb_perror_msg(msg, "PACKET");
     239    }
    181240    return result;
    182241}
    183242
    184 
    185243/* Let the kernel do all the work for packet generation */
    186 int udhcp_kernel_packet(struct dhcpMessage *payload,
    187         uint32_t source_ip, int source_port,
    188         uint32_t dest_ip, int dest_port)
    189 {
    190     int fd, result;
     244int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt,
     245        uint32_t source_nip, int source_port,
     246        uint32_t dest_nip, int dest_port)
     247{
    191248    struct sockaddr_in client;
     249    unsigned padding;
     250    int fd;
     251    int result = -1;
     252    const char *msg;
    192253
    193254    fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    194     if (fd < 0)
    195         return -1;
    196 
     255    if (fd < 0) {
     256        msg = "socket(%s)";
     257        goto ret_msg;
     258    }
    197259    setsockopt_reuseaddr(fd);
    198260
     
    200262    client.sin_family = AF_INET;
    201263    client.sin_port = htons(source_port);
    202     client.sin_addr.s_addr = source_ip;
    203 
     264    client.sin_addr.s_addr = source_nip;
    204265    if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) {
    205         close(fd);
    206         return -1;
     266        msg = "bind(%s)";
     267        goto ret_close;
    207268    }
    208269
     
    210271    client.sin_family = AF_INET;
    211272    client.sin_port = htons(dest_port);
    212     client.sin_addr.s_addr = dest_ip;
    213 
    214     if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) {
    215         close(fd);
    216         return -1;
    217     }
    218 
    219     result = write(fd, payload, sizeof(struct dhcpMessage));
     273    client.sin_addr.s_addr = dest_nip;
     274    if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) {
     275        msg = "connect";
     276        goto ret_close;
     277    }
     278
     279    udhcp_dump_packet(dhcp_pkt);
     280
     281    padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options);
     282    result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding);
     283    msg = "write";
     284 ret_close:
    220285    close(fd);
     286    if (result < 0) {
     287 ret_msg:
     288        bb_perror_msg(msg, "UDP");
     289    }
    221290    return result;
    222291}
  • branches/2.2.9/mindi-busybox/networking/udhcp/signalpipe.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    2 /* signalpipe.c
    3  *
     2/*
    43 * Signal pipe infrastructure. A reliable way of delivering signals.
    54 *
     
    2019 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    2120 */
    22 
    2321#include "common.h"
    2422
    25 
    26 static int signal_pipe[2];
     23/* Global variable: we access it from signal handler */
     24static struct fd_pair signal_pipe;
    2725
    2826static void signal_handler(int sig)
    2927{
    3028    unsigned char ch = sig; /* use char, avoid dealing with partial writes */
    31     if (write(signal_pipe[1], &ch, 1) != 1)
    32         bb_perror_msg("cannot send signal");
     29    if (write(signal_pipe.wr, &ch, 1) != 1)
     30        bb_perror_msg("can't send signal");
    3331}
    34 
    3532
    3633/* Call this before doing anything else. Sets up the socket pair
    3734 * and installs the signal handler */
    38 void udhcp_sp_setup(void)
     35void FAST_FUNC udhcp_sp_setup(void)
    3936{
    4037    /* was socketpair, but it needs AF_UNIX in kernel */
    41     xpipe(signal_pipe);
    42     fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC);
    43     fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC);
    44     fcntl(signal_pipe[1], F_SETFL, O_NONBLOCK);
    45     signal(SIGUSR1, signal_handler);
    46     signal(SIGUSR2, signal_handler);
    47     signal(SIGTERM, signal_handler);
     38    xpiped_pair(signal_pipe);
     39    close_on_exec_on(signal_pipe.rd);
     40    close_on_exec_on(signal_pipe.wr);
     41    ndelay_on(signal_pipe.wr);
     42    bb_signals(0
     43        + (1 << SIGUSR1)
     44        + (1 << SIGUSR2)
     45        + (1 << SIGTERM)
     46        , signal_handler);
    4847}
    49 
    5048
    5149/* Quick little function to setup the rfds. Will return the
    5250 * max_fd for use with select. Limited in that you can only pass
    5351 * one extra fd */
    54 int udhcp_sp_fd_set(fd_set *rfds, int extra_fd)
     52int FAST_FUNC udhcp_sp_fd_set(fd_set *rfds, int extra_fd)
    5553{
    5654    FD_ZERO(rfds);
    57     FD_SET(signal_pipe[0], rfds);
     55    FD_SET(signal_pipe.rd, rfds);
    5856    if (extra_fd >= 0) {
    59         fcntl(extra_fd, F_SETFD, FD_CLOEXEC);
     57        close_on_exec_on(extra_fd);
    6058        FD_SET(extra_fd, rfds);
    6159    }
    62     return signal_pipe[0] > extra_fd ? signal_pipe[0] : extra_fd;
     60    return signal_pipe.rd > extra_fd ? signal_pipe.rd : extra_fd;
    6361}
    64 
    6562
    6663/* Read a signal from the signal pipe. Returns 0 if there is
    6764 * no signal, -1 on error (and sets errno appropriately), and
    6865 * your signal on success */
    69 int udhcp_sp_read(fd_set *rfds)
     66int FAST_FUNC udhcp_sp_read(const fd_set *rfds)
    7067{
    7168    unsigned char sig;
    7269
    73     if (!FD_ISSET(signal_pipe[0], rfds))
     70    if (!FD_ISSET(signal_pipe.rd, rfds))
    7471        return 0;
    7572
    76     if (read(signal_pipe[0], &sig, 1) != 1)
     73    if (safe_read(signal_pipe.rd, &sig, 1) != 1)
    7774        return -1;
    7875
  • branches/2.2.9/mindi-busybox/networking/udhcp/socket.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * socket.c -- DHCP server client/server socket creation
     3 * DHCP server client/server socket creation
    44 *
    55 * udhcp client/server
     
    2323 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    2424 */
    25 
    2625#include <net/if.h>
    27 #include <features.h>
    2826#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION
    29 #include <netpacket/packet.h>
    30 #include <net/ethernet.h>
     27# include <netpacket/packet.h>
     28# include <net/ethernet.h>
    3129#else
    32 #include <asm/types.h>
    33 #include <linux/if_packet.h>
    34 #include <linux/if_ether.h>
     30# include <asm/types.h>
     31# include <linux/if_packet.h>
     32# include <linux/if_ether.h>
    3533#endif
    3634
    3735#include "common.h"
    3836
    39 
    40 int read_interface(const char *interface, int *ifindex, uint32_t *addr, uint8_t *arp)
     37int FAST_FUNC udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac)
    4138{
    4239    int fd;
     
    4845
    4946    ifr.ifr_addr.sa_family = AF_INET;
    50     strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
    51     if (addr) {
     47    strncpy_IFNAMSIZ(ifr.ifr_name, interface);
     48    if (nip) {
    5249        if (ioctl_or_perror(fd, SIOCGIFADDR, &ifr,
    5350            "is interface %s up and configured?", interface)
     
    5754        }
    5855        our_ip = (struct sockaddr_in *) &ifr.ifr_addr;
    59         *addr = our_ip->sin_addr.s_addr;
    60         DEBUG("%s (our ip) = %s", ifr.ifr_name, inet_ntoa(our_ip->sin_addr));
     56        *nip = our_ip->sin_addr.s_addr;
     57        log1("IP %s", inet_ntoa(our_ip->sin_addr));
    6158    }
    6259
     
    6663            return -1;
    6764        }
    68         DEBUG("adapter index %d", ifr.ifr_ifindex);
     65        log1("Adapter index %d", ifr.ifr_ifindex);
    6966        *ifindex = ifr.ifr_ifindex;
    7067    }
    7168
    72     if (arp) {
     69    if (mac) {
    7370        if (ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr) != 0) {
    7471            close(fd);
    7572            return -1;
    7673        }
    77         memcpy(arp, ifr.ifr_hwaddr.sa_data, 6);
    78         DEBUG("adapter hardware address %02x:%02x:%02x:%02x:%02x:%02x",
    79             arp[0], arp[1], arp[2], arp[3], arp[4], arp[5]);
     74        memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
     75        log1("MAC %02x:%02x:%02x:%02x:%02x:%02x",
     76            mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    8077    }
    8178
     
    8683/* 1. None of the callers expects it to ever fail */
    8784/* 2. ip was always INADDR_ANY */
    88 int listen_socket(/*uint32_t ip,*/ int port, const char *inf)
     85int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf)
    8986{
    9087    int fd;
    91     struct ifreq interface;
    9288    struct sockaddr_in addr;
    9389
    94     DEBUG("Opening listen socket on *:%d %s", port, inf);
     90    log1("Opening listen socket on *:%d %s", port, inf);
    9591    fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
    9692
     
    9995        bb_perror_msg_and_die("SO_BROADCAST");
    10096
    101     strncpy(interface.ifr_name, inf, IFNAMSIZ);
    102     if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(interface)) == -1)
    103         bb_perror_msg_and_die("SO_BINDTODEVICE");
     97    /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */
     98    if (setsockopt_bindtodevice(fd, inf))
     99        xfunc_die(); /* warning is already printed */
    104100
    105101    memset(&addr, 0, sizeof(addr));
  • branches/2.2.9/mindi-busybox/networking/udhcp/static_leases.c

    r1765 r2725  
    11/* vi: set sw=4 ts=4: */
    22/*
    3  * static_leases.c -- Couple of functions to assist with storing and
    4  * retrieving data for static leases
     3 * Storing and retrieving data for static leases
    54 *
    65 * Wade Berrier <wberrier@myrealbox.com> September 2004
    76 *
     7 * Licensed under GPLv2, see file LICENSE in this source tree.
    88 */
    9 
    109#include "common.h"
    1110#include "dhcpd.h"
    1211
     12/* Takes the address of the pointer to the static_leases linked list,
     13 * address to a 6 byte mac address,
     14 * 4 byte IP address */
     15void FAST_FUNC add_static_lease(struct static_lease **st_lease_pp,
     16        uint8_t *mac,
     17        uint32_t nip)
     18{
     19    struct static_lease *st_lease;
    1320
    14 /* Takes the address of the pointer to the static_leases linked list,
    15  *   Address to a 6 byte mac address
    16  *   Address to a 4 byte ip address */
    17 int addStaticLease(struct static_lease **lease_struct, uint8_t *mac, uint32_t *ip)
     21    /* Find the tail of the list */
     22    while ((st_lease = *st_lease_pp) != NULL) {
     23        st_lease_pp = &st_lease->next;
     24    }
     25
     26    /* Add new node */
     27    *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease));
     28    memcpy(st_lease->mac, mac, 6);
     29    st_lease->nip = nip;
     30    /*st_lease->next = NULL;*/
     31}
     32
     33/* Find static lease IP by mac */
     34uint32_t FAST_FUNC get_static_nip_by_mac(struct static_lease *st_lease, void *mac)
     35{
     36    while (st_lease) {
     37        if (memcmp(st_lease->mac, mac, 6) == 0)
     38            return st_lease->nip;
     39        st_lease = st_lease->next;
     40    }
     41
     42    return 0;
     43}
     44
     45/* Check to see if an IP is reserved as a static IP */
     46int FAST_FUNC is_nip_reserved(struct static_lease *st_lease, uint32_t nip)
     47{
     48    while (st_lease) {
     49        if (st_lease->nip == nip)
     50            return 1;
     51        st_lease = st_lease->next;
     52    }
     53
     54    return 0;
     55}
     56
     57#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
     58/* Print out static leases just to check what's going on */
     59/* Takes the address of the pointer to the static_leases linked list */
     60void FAST_FUNC log_static_leases(struct static_lease **st_lease_pp)
    1861{
    1962    struct static_lease *cur;
    20     struct static_lease *new_static_lease;
    2163
    22     /* Build new node */
    23     new_static_lease = xmalloc(sizeof(struct static_lease));
    24     new_static_lease->mac = mac;
    25     new_static_lease->ip = ip;
    26     new_static_lease->next = NULL;
     64    if (dhcp_verbose < 2)
     65        return;
    2766
    28     /* If it's the first node to be added... */
    29     if (*lease_struct == NULL) {
    30         *lease_struct = new_static_lease;
    31     } else {
    32         cur = *lease_struct;
    33         while (cur->next) {
    34             cur = cur->next;
    35         }
    36 
    37         cur->next = new_static_lease;
    38     }
    39 
    40     return 1;
    41 }
    42 
    43 /* Check to see if a mac has an associated static lease */
    44 uint32_t getIpByMac(struct static_lease *lease_struct, void *arg)
    45 {
    46     uint32_t return_ip;
    47     struct static_lease *cur = lease_struct;
    48     uint8_t *mac = arg;
    49 
    50     return_ip = 0;
    51 
     67    cur = *st_lease_pp;
    5268    while (cur) {
    53         /* If the client has the correct mac  */
    54         if (memcmp(cur->mac, mac, 6) == 0) {
    55             return_ip = *(cur->ip);
    56         }
    57 
    58         cur = cur->next;
    59     }
    60 
    61     return return_ip;
    62 }
    63 
    64 /* Check to see if an ip is reserved as a static ip */
    65 uint32_t reservedIp(struct static_lease *lease_struct, uint32_t ip)
    66 {
    67     struct static_lease *cur = lease_struct;
    68 
    69     uint32_t return_val = 0;
    70 
    71     while (cur) {
    72         /* If the client has the correct ip  */
    73         if (*cur->ip == ip)
    74             return_val = 1;
    75 
    76         cur = cur->next;
    77     }
    78 
    79     return return_val;
    80 }
    81 
    82 #if ENABLE_FEATURE_UDHCP_DEBUG
    83 /* Print out static leases just to check what's going on */
    84 /* Takes the address of the pointer to the static_leases linked list */
    85 void printStaticLeases(struct static_lease **arg)
    86 {
    87     /* Get a pointer to the linked list */
    88     struct static_lease *cur = *arg;
    89 
    90     while (cur) {
    91         /* printf("PrintStaticLeases: Lease mac Address: %x\n", cur->mac); */
    92         printf("PrintStaticLeases: Lease mac Value: %x\n", *(cur->mac));
    93         /* printf("PrintStaticLeases: Lease ip Address: %x\n", cur->ip); */
    94         printf("PrintStaticLeases: Lease ip Value: %x\n", *(cur->ip));
    95 
     69        bb_info_msg("static lease: mac:%02x:%02x:%02x:%02x:%02x:%02x nip:%x",
     70            cur->mac[0], cur->mac[1], cur->mac[2],
     71            cur->mac[3], cur->mac[4], cur->mac[5],
     72            cur->nip
     73        );
    9674        cur = cur->next;
    9775    }
Note: See TracChangeset for help on using the changeset viewer.