busybox/networking/udhcp/dhcpd.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * udhcp server
   4 * Copyright (C) 1999 Matthew Ramsay <matthewr@moreton.com.au>
   5 *                      Chris Trew <ctrew@moreton.com.au>
   6 *
   7 * Rewrite by Russ Dill <Russ.Dill@asu.edu> July 2001
   8 *
   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.
  22 */
  23//applet:IF_UDHCPD(APPLET(udhcpd, BB_DIR_USR_SBIN, BB_SUID_DROP))
  24
  25//kbuild:lib-$(CONFIG_UDHCPD) += common.o packet.o signalpipe.o socket.o
  26//kbuild:lib-$(CONFIG_UDHCPD) += dhcpd.o arpping.o
  27//kbuild:lib-$(CONFIG_FEATURE_UDHCP_RFC3397) += domain_codec.o
  28
  29//usage:#define udhcpd_trivial_usage
  30//usage:       "[-fS] [-I ADDR] [-a MSEC]" IF_FEATURE_UDHCP_PORT(" [-P PORT]") " [CONFFILE]"
  31//usage:#define udhcpd_full_usage "\n\n"
  32//usage:       "DHCP server\n"
  33//usage:     "\n        -f      Run in foreground"
  34//usage:     "\n        -S      Log to syslog too"
  35//usage:     "\n        -I ADDR Local address"
  36//usage:     "\n        -a MSEC Timeout for ARP ping (default 2000)"
  37//usage:        IF_FEATURE_UDHCP_PORT(
  38//usage:     "\n        -P PORT Use PORT (default 67)"
  39//usage:        )
  40//usage:     "\nSignals:"
  41//usage:     "\n        USR1    Update lease file"
  42
  43#include <netinet/ether.h>
  44#include <syslog.h>
  45#include "common.h"
  46#include "dhcpc.h"
  47#include "dhcpd.h"
  48
  49#if ENABLE_PID_FILE_PATH
  50#define PID_FILE_PATH CONFIG_PID_FILE_PATH
  51#else
  52#define PID_FILE_PATH "/var/run"
  53#endif
  54
  55/* globals */
  56#define g_leases ((struct dyn_lease*)ptr_to_globals)
  57/* struct server_data_t server_data is in bb_common_bufsiz1 */
  58
  59struct static_lease {
  60        struct static_lease *next;
  61        uint32_t nip;
  62        uint8_t mac[6];
  63        uint8_t opt[1];
  64};
  65
  66/* Takes the address of the pointer to the static_leases linked list,
  67 * address to a 6 byte mac address,
  68 * 4 byte IP address */
  69static void add_static_lease(struct static_lease **st_lease_pp,
  70                uint8_t *mac,
  71                uint32_t nip,
  72                const char *opts)
  73{
  74        struct static_lease *st_lease;
  75        unsigned optlen;
  76
  77        optlen = (opts ? 1+1+strnlen(opts, 120) : 0);
  78
  79        /* Find the tail of the list */
  80        while ((st_lease = *st_lease_pp) != NULL) {
  81                st_lease_pp = &st_lease->next;
  82        }
  83
  84        /* Add new node */
  85        *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease) + optlen);
  86        memcpy(st_lease->mac, mac, 6);
  87        st_lease->nip = nip;
  88        /*st_lease->next = NULL;*/
  89        if (optlen) {
  90                st_lease->opt[OPT_CODE] = DHCP_HOST_NAME;
  91                optlen -= 2;
  92                st_lease->opt[OPT_LEN] = optlen;
  93                memcpy(&st_lease->opt[OPT_DATA], opts, optlen);
  94        }
  95
  96#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
  97        /* Print out static leases just to check what's going on */
  98        if (dhcp_verbose >= 2) {
  99                bb_info_msg("static lease: mac:%02x:%02x:%02x:%02x:%02x:%02x nip:%x",
 100                        st_lease->mac[0], st_lease->mac[1], st_lease->mac[2],
 101                        st_lease->mac[3], st_lease->mac[4], st_lease->mac[5],
 102                        st_lease->nip
 103                );
 104        }
 105#endif
 106}
 107
 108/* Find static lease IP by mac */
 109static uint32_t get_static_nip_by_mac(void *mac)
 110{
 111        struct static_lease *st_lease = server_data.static_leases;
 112
 113        while (st_lease) {
 114                if (memcmp(st_lease->mac, mac, 6) == 0)
 115                        return st_lease->nip;
 116                st_lease = st_lease->next;
 117        }
 118
 119        return 0;
 120}
 121
 122static int is_nip_reserved_as_static(uint32_t nip)
 123{
 124        struct static_lease *st_lease = server_data.static_leases;
 125
 126        while (st_lease) {
 127                if (st_lease->nip == nip)
 128                        return 1;
 129                st_lease = st_lease->next;
 130        }
 131
 132        return 0;
 133}
 134
 135/* Find the oldest expired lease, NULL if there are no expired leases */
 136static struct dyn_lease *oldest_expired_lease(void)
 137{
 138        struct dyn_lease *oldest_lease = NULL;
 139        leasetime_t oldest_time = time(NULL);
 140        unsigned i;
 141
 142        /* Unexpired leases have g_leases[i].expires >= current time
 143         * and therefore can't ever match */
 144        for (i = 0; i < server_data.max_leases; i++) {
 145                if (g_leases[i].expires == 0 /* empty entry */
 146                 || g_leases[i].expires < oldest_time
 147                ) {
 148                        oldest_time = g_leases[i].expires;
 149                        oldest_lease = &g_leases[i];
 150                }
 151        }
 152        return oldest_lease;
 153}
 154
 155/* Clear out all leases with matching nonzero chaddr OR yiaddr.
 156 * If chaddr == NULL, this is a conflict lease.
 157 */
 158static void clear_leases(const uint8_t *chaddr, uint32_t yiaddr)
 159{
 160        unsigned i;
 161
 162        for (i = 0; i < server_data.max_leases; i++) {
 163                if ((chaddr && memcmp(g_leases[i].lease_mac, chaddr, 6) == 0)
 164                 || (yiaddr && g_leases[i].lease_nip == yiaddr)
 165                ) {
 166                        memset(&g_leases[i], 0, sizeof(g_leases[i]));
 167                }
 168        }
 169}
 170
 171/* Add a lease into the table, clearing out any old ones.
 172 * If chaddr == NULL, this is a conflict lease.
 173 */
 174static struct dyn_lease *add_lease(
 175                const uint8_t *chaddr, uint32_t yiaddr,
 176                leasetime_t leasetime,
 177                const char *hostname, int hostname_len)
 178{
 179        struct dyn_lease *oldest;
 180
 181        /* clean out any old ones */
 182        clear_leases(chaddr, yiaddr);
 183
 184        oldest = oldest_expired_lease();
 185
 186        if (oldest) {
 187                memset(oldest, 0, sizeof(*oldest));
 188                if (hostname) {
 189                        char *p;
 190
 191                        hostname_len++; /* include NUL */
 192                        if (hostname_len > sizeof(oldest->hostname))
 193                                hostname_len = sizeof(oldest->hostname);
 194                        p = safe_strncpy(oldest->hostname, hostname, hostname_len);
 195                        /*
 196                         * Sanitization (s/bad_char/./g).
 197                         * The intent is not to allow only "DNS-valid" hostnames,
 198                         * but merely make dumpleases output safe for shells to use.
 199                         * We accept "0-9A-Za-z._-", all other chars turn to dots.
 200                         */
 201                        if (*p == '-')
 202                                *p = '.'; /* defeat "-option" attacks too */
 203                        while (*p) {
 204                                if (!isalnum(*p) && *p != '-' && *p != '_')
 205                                        *p = '.';
 206                                p++;
 207                        }
 208                }
 209                if (chaddr)
 210                        memcpy(oldest->lease_mac, chaddr, 6);
 211                oldest->lease_nip = yiaddr;
 212                oldest->expires = time(NULL) + leasetime;
 213        }
 214
 215        return oldest;
 216}
 217
 218/* True if a lease has expired */
 219static int is_expired_lease(struct dyn_lease *lease)
 220{
 221        return (lease->expires < (leasetime_t) time(NULL));
 222}
 223
 224/* Find the first lease that matches MAC, NULL if no match */
 225static struct dyn_lease *find_lease_by_mac(const uint8_t *mac)
 226{
 227        unsigned i;
 228
 229        for (i = 0; i < server_data.max_leases; i++)
 230                if (memcmp(g_leases[i].lease_mac, mac, 6) == 0)
 231                        return &g_leases[i];
 232
 233        return NULL;
 234}
 235
 236/* Find the first lease that matches IP, NULL is no match */
 237static struct dyn_lease *find_lease_by_nip(uint32_t nip)
 238{
 239        unsigned i;
 240
 241        for (i = 0; i < server_data.max_leases; i++)
 242                if (g_leases[i].lease_nip == nip)
 243                        return &g_leases[i];
 244
 245        return NULL;
 246}
 247
 248/* Check if the IP is taken; if it is, add it to the lease table */
 249static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac, unsigned arpping_ms)
 250{
 251        struct in_addr temp;
 252        int r;
 253
 254        r = arpping(nip, safe_mac,
 255                        server_data.server_nip,
 256                        server_data.server_mac,
 257                        server_data.interface,
 258                        arpping_ms);
 259        if (r)
 260                return r;
 261
 262        temp.s_addr = nip;
 263        bb_info_msg("%s belongs to someone, reserving it for %u seconds",
 264                inet_ntoa(temp), (unsigned)server_data.conflict_time);
 265        add_lease(NULL, nip, server_data.conflict_time, NULL, 0);
 266        return 0;
 267}
 268
 269/* Find a new usable (we think) address */
 270static uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arpping_ms)
 271{
 272        uint32_t addr;
 273        struct dyn_lease *oldest_lease = NULL;
 274
 275#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC
 276        uint32_t stop;
 277        unsigned i, hash;
 278
 279        /* hash hwaddr: use the SDBM hashing algorithm.  Seems to give good
 280         * dispersal even with similarly-valued "strings".
 281         */
 282        hash = 0;
 283        for (i = 0; i < 6; i++)
 284                hash += safe_mac[i] + (hash << 6) + (hash << 16) - hash;
 285
 286        /* pick a seed based on hwaddr then iterate until we find a free address. */
 287        addr = server_data.start_ip
 288                + (hash % (1 + server_data.end_ip - server_data.start_ip));
 289        stop = addr;
 290#else
 291        addr = server_data.start_ip;
 292#define stop (server_data.end_ip + 1)
 293#endif
 294        do {
 295                uint32_t nip;
 296                struct dyn_lease *lease;
 297
 298                /* (Addresses ending in .0 or .255 can legitimately be allocated
 299                 * in various situations, so _don't_ skip these.  The user needs
 300                 * to choose start_ip and end_ip correctly for a particular
 301                 * network environment.) */
 302
 303                nip = htonl(addr);
 304                /* skip our own address */
 305                if (nip == server_data.server_nip)
 306                        goto next_addr;
 307                /* is this a static lease addr? */
 308                if (is_nip_reserved_as_static(nip))
 309                        goto next_addr;
 310
 311                lease = find_lease_by_nip(nip);
 312                if (!lease) {
 313//TODO: DHCP servers do not always sit on the same subnet as clients: should *ping*, not arp-ping!
 314                        if (nobody_responds_to_arp(nip, safe_mac, arpping_ms))
 315                                return nip;
 316                } else {
 317                        if (!oldest_lease || lease->expires < oldest_lease->expires)
 318                                oldest_lease = lease;
 319                }
 320
 321 next_addr:
 322                addr++;
 323#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC
 324                if (addr > server_data.end_ip)
 325                        addr = server_data.start_ip;
 326#endif
 327        } while (addr != stop);
 328
 329        if (oldest_lease
 330         && is_expired_lease(oldest_lease)
 331         && nobody_responds_to_arp(oldest_lease->lease_nip, safe_mac, arpping_ms)
 332        ) {
 333                return oldest_lease->lease_nip;
 334        }
 335
 336        return 0;
 337}
 338
 339/* On these functions, make sure your datatype matches */
 340static int FAST_FUNC read_str(const char *line, void *arg)
 341{
 342        char **dest = arg;
 343
 344        free(*dest);
 345        *dest = xstrdup(line);
 346        return 1;
 347}
 348
 349static int FAST_FUNC read_u32(const char *line, void *arg)
 350{
 351        *(uint32_t*)arg = bb_strtou32(line, NULL, 10);
 352        return errno == 0;
 353}
 354
 355static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
 356{
 357        char *line;
 358        char *mac_string;
 359        char *ip_string;
 360        char *opts;
 361        struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */
 362        uint32_t nip;
 363
 364        /* Read mac */
 365        line = (char *) const_line;
 366        mac_string = strtok_r(line, " \t", &line);
 367        if (!mac_string || !ether_aton_r(mac_string, &mac_bytes))
 368                return 0;
 369
 370        /* Read ip */
 371        ip_string = strtok_r(NULL, " \t", &line);
 372        if (!ip_string || !udhcp_str2nip(ip_string, &nip))
 373                return 0;
 374
 375        opts = strtok_r(NULL, " \t", &line);
 376        /* opts might be NULL, that's not an error */
 377
 378        add_static_lease(arg, (uint8_t*) &mac_bytes, nip, opts);
 379
 380        return 1;
 381}
 382
 383static int FAST_FUNC read_optset(const char *line, void *arg)
 384{
 385        return udhcp_str2optset(line, arg,
 386                        dhcp_optflags, dhcp_option_strings,
 387                        /*dhcpv6:*/ 0
 388        );
 389}
 390
 391struct config_keyword {
 392        const char *keyword;
 393        int (*handler)(const char *line, void *var) FAST_FUNC;
 394        unsigned ofs;
 395        const char *def;
 396};
 397
 398#define OFS(field) offsetof(struct server_data_t, field)
 399
 400static const struct config_keyword keywords[] ALIGN_PTR = {
 401        /* keyword        handler           variable address    default */
 402        {"start"        , udhcp_str2nip   , OFS(start_ip     ), "192.168.0.20"},
 403        {"end"          , udhcp_str2nip   , OFS(end_ip       ), "192.168.0.254"},
 404        {"interface"    , read_str        , OFS(interface    ), "eth0"},
 405        /* Avoid "max_leases value not sane" warning by setting default
 406         * to default_end_ip - default_start_ip + 1: */
 407        {"max_leases"   , read_u32        , OFS(max_leases   ), "235"},
 408        {"auto_time"    , read_u32        , OFS(auto_time    ), "7200"},
 409        {"decline_time" , read_u32        , OFS(decline_time ), "3600"},
 410        {"conflict_time", read_u32        , OFS(conflict_time), "3600"},
 411        {"offer_time"   , read_u32        , OFS(offer_time   ), "60"},
 412        {"min_lease"    , read_u32        , OFS(min_lease_sec), "60"},
 413        {"lease_file"   , read_str        , OFS(lease_file   ), LEASES_FILE},
 414        {"pidfile"      , read_str        , OFS(pidfile      ), PID_FILE_PATH "/udhcpd.pid"},
 415        {"siaddr"       , udhcp_str2nip   , OFS(siaddr_nip   ), "0.0.0.0"},
 416        /* keywords with no defaults must be last! */
 417        {"option"       , read_optset     , OFS(options      ), ""},
 418        {"opt"          , read_optset     , OFS(options      ), ""},
 419        {"notify_file"  , read_str        , OFS(notify_file  ), NULL},
 420        {"sname"        , read_str        , OFS(sname        ), NULL},
 421        {"boot_file"    , read_str        , OFS(boot_file    ), NULL},
 422        {"static_lease" , read_staticlease, OFS(static_leases), ""},
 423};
 424enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 };
 425
 426static NOINLINE void read_config(const char *file)
 427{
 428        parser_t *parser;
 429        const struct config_keyword *k;
 430        unsigned i;
 431        char *token[2];
 432
 433        for (i = 0; i < KWS_WITH_DEFAULTS; i++)
 434                keywords[i].handler(keywords[i].def, (char*)&server_data + keywords[i].ofs);
 435
 436        parser = config_open(file);
 437        while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) {
 438                for (k = keywords, i = 0; i < ARRAY_SIZE(keywords); k++, i++) {
 439                        if (strcasecmp(token[0], k->keyword) == 0) {
 440                                if (!k->handler(token[1], (char*)&server_data + k->ofs)) {
 441                                        bb_error_msg("can't parse line %u in %s",
 442                                                        parser->lineno, file);
 443                                        /* reset back to the default value */
 444                                        k->handler(k->def, (char*)&server_data + k->ofs);
 445                                }
 446                                break;
 447                        }
 448                }
 449        }
 450        config_close(parser);
 451
 452        server_data.start_ip = ntohl(server_data.start_ip);
 453        server_data.end_ip = ntohl(server_data.end_ip);
 454        if (server_data.start_ip > server_data.end_ip)
 455                bb_error_msg_and_die("bad start/end IP range in %s", file);
 456}
 457
 458static void write_leases(void)
 459{
 460        int fd;
 461        unsigned i;
 462        leasetime_t curr;
 463        int64_t written_at;
 464
 465        fd = open_or_warn(server_data.lease_file, O_WRONLY|O_CREAT|O_TRUNC);
 466        if (fd < 0)
 467                return;
 468
 469        curr = written_at = time(NULL);
 470
 471        written_at = SWAP_BE64(written_at);
 472        full_write(fd, &written_at, sizeof(written_at));
 473
 474        for (i = 0; i < server_data.max_leases; i++) {
 475                leasetime_t tmp_time;
 476
 477                if (g_leases[i].lease_nip == 0)
 478                        continue;
 479
 480                /* Screw with the time in the struct, for easier writing */
 481                tmp_time = g_leases[i].expires;
 482
 483                g_leases[i].expires -= curr;
 484                if ((signed_leasetime_t) g_leases[i].expires < 0)
 485                        g_leases[i].expires = 0;
 486                g_leases[i].expires = htonl(g_leases[i].expires);
 487
 488                /* No error check. If the file gets truncated,
 489                 * we lose some leases on restart. Oh well. */
 490                full_write(fd, &g_leases[i], sizeof(g_leases[i]));
 491
 492                /* Then restore it when done */
 493                g_leases[i].expires = tmp_time;
 494        }
 495        close(fd);
 496
 497        if (server_data.notify_file) {
 498                char *argv[3];
 499                argv[0] = server_data.notify_file;
 500                argv[1] = server_data.lease_file;
 501                argv[2] = NULL;
 502                spawn_and_wait(argv);
 503        }
 504}
 505
 506static NOINLINE void read_leases(const char *file)
 507{
 508        struct dyn_lease lease;
 509        int64_t written_at, time_passed;
 510        int fd;
 511#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
 512        unsigned i = 0;
 513#endif
 514
 515        fd = open_or_warn(file, O_RDONLY);
 516        if (fd < 0)
 517                return;
 518
 519        if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at))
 520                goto ret;
 521        written_at = SWAP_BE64(written_at);
 522
 523        time_passed = time(NULL) - written_at;
 524        /* Strange written_at, or lease file from old version of udhcpd
 525         * which had no "written_at" field? */
 526        if ((uint64_t)time_passed > 12 * 60 * 60)
 527                goto ret;
 528
 529        while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
 530                uint32_t y = ntohl(lease.lease_nip);
 531                if (y >= server_data.start_ip && y <= server_data.end_ip) {
 532                        signed_leasetime_t expires = ntohl(lease.expires) - (signed_leasetime_t)time_passed;
 533                        uint32_t static_nip;
 534
 535                        if (expires <= 0)
 536                                /* We keep expired leases: add_lease() will add
 537                                 * a lease with 0 seconds remaining.
 538                                 * Fewer IP address changes this way for mass reboot scenario.
 539                                 */
 540                                expires = 0;
 541
 542                        /* Check if there is a different static lease for this IP or MAC */
 543                        static_nip = get_static_nip_by_mac(lease.lease_mac);
 544                        if (static_nip) {
 545                                /* NB: we do not add lease even if static_nip == lease.lease_nip.
 546                                 */
 547                                continue;
 548                        }
 549                        if (is_nip_reserved_as_static(lease.lease_nip))
 550                                continue;
 551
 552                        /* NB: add_lease takes "relative time", IOW,
 553                         * lease duration, not lease deadline. */
 554                        if (add_lease(lease.lease_mac, lease.lease_nip,
 555                                        expires,
 556                                        lease.hostname, sizeof(lease.hostname)
 557                                ) == 0
 558                        ) {
 559                                bb_error_msg("too many leases while loading %s", file);
 560                                break;
 561                        }
 562#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
 563                        i++;
 564#endif
 565                }
 566        }
 567        log1("read %d leases", i);
 568 ret:
 569        close(fd);
 570}
 571
 572/* Send a packet to a specific mac address and ip address by creating our own ip packet */
 573static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast)
 574{
 575        const uint8_t *chaddr;
 576        uint32_t ciaddr;
 577
 578        // Was:
 579        //if (force_broadcast) { /* broadcast */ }
 580        //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
 581        //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
 582        //else { /* unicast to dhcp_pkt->yiaddr */ }
 583        // But this is wrong: yiaddr is _our_ idea what client's IP is
 584        // (for example, from lease file). Client may not know that,
 585        // and may not have UDP socket listening on that IP!
 586        // We should never unicast to dhcp_pkt->yiaddr!
 587        // dhcp_pkt->ciaddr, OTOH, comes from client's request packet,
 588        // and can be used.
 589
 590        if (force_broadcast
 591         || (dhcp_pkt->flags & htons(BROADCAST_FLAG))
 592         || dhcp_pkt->ciaddr == 0
 593        ) {
 594                log1s("broadcasting packet to client");
 595                ciaddr = INADDR_BROADCAST;
 596                chaddr = MAC_BCAST_ADDR;
 597        } else {
 598                log1s("unicasting packet to client ciaddr");
 599                ciaddr = dhcp_pkt->ciaddr;
 600                chaddr = dhcp_pkt->chaddr;
 601        }
 602
 603        udhcp_send_raw_packet(dhcp_pkt,
 604                /*src*/ server_data.server_nip, SERVER_PORT,
 605                /*dst*/ ciaddr, CLIENT_PORT, chaddr,
 606                server_data.ifindex);
 607}
 608
 609/* Send a packet to gateway_nip using the kernel ip stack */
 610static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
 611{
 612        log1s("forwarding packet to relay");
 613
 614        udhcp_send_kernel_packet(dhcp_pkt,
 615                        server_data.server_nip, SERVER_PORT,
 616                        dhcp_pkt->gateway_nip, SERVER_PORT,
 617        /* Yes, relay agents receive (and send) all their packets on SERVER_PORT,
 618         * even those which are clients' requests and would normally
 619         * (i.e. without relay) use CLIENT_PORT. See RFC 1542.
 620         */
 621                        server_data.interface);
 622}
 623
 624static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
 625{
 626        if (dhcp_pkt->gateway_nip)
 627                send_packet_to_relay(dhcp_pkt);
 628        else
 629                send_packet_to_client(dhcp_pkt, force_broadcast);
 630}
 631
 632static void send_packet_verbose(struct dhcp_packet *dhcp_pkt, const char *fmt)
 633{
 634        struct in_addr addr;
 635        addr.s_addr = dhcp_pkt->yiaddr;
 636        bb_info_msg(fmt, inet_ntoa(addr));
 637        /* send_packet emits error message itself if it detects failure */
 638        send_packet(dhcp_pkt, /*force_bcast:*/ 0);
 639}
 640
 641static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
 642{
 643        /* Sets op, htype, hlen, cookie fields
 644         * and adds DHCP_MESSAGE_TYPE option */
 645        udhcp_init_header(packet, type);
 646
 647        packet->xid = oldpacket->xid;
 648        memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr));
 649        packet->flags = oldpacket->flags;
 650        packet->gateway_nip = oldpacket->gateway_nip;
 651        packet->ciaddr = oldpacket->ciaddr;
 652        udhcp_add_simple_option(packet, DHCP_SERVER_ID, server_data.server_nip);
 653}
 654
 655/* Fill options field, siaddr_nip, and sname and boot_file fields.
 656 * TODO: teach this code to use overload option.
 657 */
 658static void add_server_options(struct dhcp_packet *packet)
 659{
 660        struct option_set *config_opts;
 661        uint8_t *client_hostname_opt;
 662
 663        client_hostname_opt = NULL;
 664        if (packet->yiaddr) { /* if we aren't from send_inform()... */
 665                struct static_lease *st_lease = server_data.static_leases;
 666                while (st_lease) {
 667                        if (st_lease->nip == packet->yiaddr) {
 668                                if (st_lease->opt[0] != 0)
 669                                        client_hostname_opt = st_lease->opt;
 670                                break;
 671                        }
 672                        st_lease = st_lease->next;
 673                }
 674        }
 675
 676        config_opts = server_data.options;
 677        while (config_opts) {
 678                if (config_opts->data[OPT_CODE] != DHCP_LEASE_TIME) {
 679                        /* ^^^^
 680                         * DHCP_LEASE_TIME is already filled, or in case of
 681                         * send_inform(), should not be filled at all.
 682                         */
 683                        if (config_opts->data[OPT_CODE] != DHCP_HOST_NAME
 684                         || !client_hostname_opt
 685                        ) {
 686                                /* Why "!client_hostname_opt":
 687                                 * add hostname only if client has no hostname
 688                                 * on its static lease line.
 689                                 * (Not that "opt hostname HOST"
 690                                 * makes much sense in udhcpd.conf,
 691                                 * that'd give all clients the same hostname,
 692                                 * but it's a valid configuration).
 693                                 */
 694                                udhcp_add_binary_option(packet, config_opts->data);
 695                        }
 696                }
 697                config_opts = config_opts->next;
 698        }
 699
 700        if (client_hostname_opt)
 701                udhcp_add_binary_option(packet, client_hostname_opt);
 702
 703        packet->siaddr_nip = server_data.siaddr_nip;
 704
 705        if (server_data.sname)
 706                strncpy((char*)packet->sname, server_data.sname, sizeof(packet->sname) - 1);
 707        if (server_data.boot_file)
 708                strncpy((char*)packet->file, server_data.boot_file, sizeof(packet->file) - 1);
 709}
 710
 711static uint32_t select_lease_time(struct dhcp_packet *packet)
 712{
 713        uint32_t lease_time_sec = server_data.max_lease_sec;
 714        uint8_t *lease_time_opt = udhcp_get_option32(packet, DHCP_LEASE_TIME);
 715        if (lease_time_opt) {
 716                move_from_unaligned32(lease_time_sec, lease_time_opt);
 717                lease_time_sec = ntohl(lease_time_sec);
 718                if (lease_time_sec > server_data.max_lease_sec)
 719                        lease_time_sec = server_data.max_lease_sec;
 720                if (lease_time_sec < server_data.min_lease_sec)
 721                        lease_time_sec = server_data.min_lease_sec;
 722        }
 723        return lease_time_sec;
 724}
 725
 726/* We got a DHCP DISCOVER. Send an OFFER. */
 727/* NOINLINE: limit stack usage in caller */
 728static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
 729                uint32_t static_lease_nip,
 730                struct dyn_lease *lease,
 731                uint32_t requested_nip,
 732                unsigned arpping_ms)
 733{
 734        struct dhcp_packet packet;
 735        uint32_t lease_time_sec;
 736
 737        init_packet(&packet, oldpacket, DHCPOFFER);
 738
 739        /* If it is a static lease, use its IP */
 740        packet.yiaddr = static_lease_nip;
 741        /* Else: */
 742        if (!static_lease_nip) {
 743                /* We have no static lease for client's chaddr */
 744                const char *p_host_name;
 745
 746                if (lease) {
 747                        /* We have a dynamic lease for client's chaddr.
 748                         * Reuse its IP (even if lease is expired).
 749                         * Note that we ignore requested IP in this case.
 750                         */
 751                        packet.yiaddr = lease->lease_nip;
 752                }
 753                /* Or: if client has requested an IP */
 754                else if (requested_nip != 0
 755                 /* and the IP is in the lease range */
 756                 && ntohl(requested_nip) >= server_data.start_ip
 757                 && ntohl(requested_nip) <= server_data.end_ip
 758                 /* and */
 759                 && (  !(lease = find_lease_by_nip(requested_nip)) /* is not already taken */
 760                    || is_expired_lease(lease) /* or is taken, but expired */
 761                    )
 762                ) {
 763                        packet.yiaddr = requested_nip;
 764                }
 765                else {
 766                        /* Otherwise, find a free IP */
 767                        packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr, arpping_ms);
 768                }
 769
 770                if (!packet.yiaddr) {
 771                        bb_simple_error_msg("no free IP addresses. OFFER abandoned");
 772                        return;
 773                }
 774                /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */
 775                p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
 776                lease = add_lease(packet.chaddr, packet.yiaddr,
 777                                server_data.offer_time,
 778                                p_host_name,
 779                                p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
 780                );
 781                if (!lease) {
 782                        bb_simple_error_msg("no free IP addresses. OFFER abandoned");
 783                        return;
 784                }
 785        }
 786
 787        lease_time_sec = select_lease_time(oldpacket);
 788        udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
 789        add_server_options(&packet);
 790
 791        /* send_packet emits error message itself if it detects failure */
 792        send_packet_verbose(&packet, "sending OFFER to %s");
 793}
 794
 795/* NOINLINE: limit stack usage in caller */
 796static NOINLINE void send_NAK(struct dhcp_packet *oldpacket)
 797{
 798        struct dhcp_packet packet;
 799
 800        init_packet(&packet, oldpacket, DHCPNAK);
 801
 802        log1("sending %s", "NAK");
 803        send_packet(&packet, /*force_bcast:*/ 1);
 804}
 805
 806/* NOINLINE: limit stack usage in caller */
 807static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
 808{
 809        struct dhcp_packet packet;
 810        uint32_t lease_time_sec;
 811        const char *p_host_name;
 812
 813        init_packet(&packet, oldpacket, DHCPACK);
 814        packet.yiaddr = yiaddr;
 815
 816        lease_time_sec = select_lease_time(oldpacket);
 817        udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
 818        add_server_options(&packet);
 819
 820        send_packet_verbose(&packet, "sending ACK to %s");
 821
 822        p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
 823        add_lease(packet.chaddr, packet.yiaddr,
 824                lease_time_sec,
 825                p_host_name,
 826                p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
 827        );
 828        if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
 829                /* rewrite the file with leases at every new acceptance */
 830                write_leases();
 831        }
 832}
 833
 834/* NOINLINE: limit stack usage in caller */
 835static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
 836{
 837        struct dhcp_packet packet;
 838
 839        /* "If a client has obtained a network address through some other means
 840         * (e.g., manual configuration), it may use a DHCPINFORM request message
 841         * to obtain other local configuration parameters.  Servers receiving a
 842         * DHCPINFORM message construct a DHCPACK message with any local
 843         * configuration parameters appropriate for the client without:
 844         * allocating a new address, checking for an existing binding, filling
 845         * in 'yiaddr' or including lease time parameters.  The servers SHOULD
 846         * unicast the DHCPACK reply to the address given in the 'ciaddr' field
 847         * of the DHCPINFORM message.
 848         * ...
 849         * The server responds to a DHCPINFORM message by sending a DHCPACK
 850         * message directly to the address given in the 'ciaddr' field
 851         * of the DHCPINFORM message.  The server MUST NOT send a lease
 852         * expiration time to the client and SHOULD NOT fill in 'yiaddr'."
 853         */
 854//TODO: do a few sanity checks: is ciaddr set?
 855//Better yet: is ciaddr == IP source addr?
 856        init_packet(&packet, oldpacket, DHCPACK);
 857        add_server_options(&packet);
 858
 859        send_packet(&packet, /*force_bcast:*/ 0);
 860        // or maybe? send_packet_verbose(&packet, "sending ACK to %s");
 861}
 862
 863int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 864int udhcpd_main(int argc UNUSED_PARAM, char **argv)
 865{
 866        int server_socket = -1, retval;
 867        unsigned timeout_end;
 868        unsigned num_ips;
 869        unsigned opt;
 870        struct option_set *option;
 871        char *str_I = str_I;
 872        const char *str_a = "2000";
 873        unsigned arpping_ms;
 874        IF_FEATURE_UDHCP_PORT(char *str_P;)
 875
 876        setup_common_bufsiz();
 877
 878        IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
 879        IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
 880
 881        /* Make sure fd 0,1,2 are open */
 882        /* Setup the signal pipe on fds 3,4 - must be before openlog() */
 883        udhcp_sp_setup();
 884
 885#define OPT_f (1 << 0)
 886#define OPT_S (1 << 1)
 887#define OPT_I (1 << 2)
 888#define OPT_v (1 << 3)
 889#define OPT_a (1 << 4)
 890#define OPT_P (1 << 5)
 891        opt = getopt32(argv, "^"
 892                "fSI:va:"IF_FEATURE_UDHCP_PORT("P:")
 893                "\0"
 894#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
 895                "vv"
 896#endif
 897                , &str_I
 898                , &str_a
 899                IF_FEATURE_UDHCP_PORT(, &str_P)
 900                IF_UDHCP_VERBOSE(, &dhcp_verbose)
 901        );
 902        if (!(opt & OPT_f)) { /* no -f */
 903                bb_daemonize_or_rexec(0, argv);
 904                logmode = LOGMODE_NONE;
 905        }
 906        /* update argv after the possible vfork+exec in daemonize */
 907        argv += optind;
 908        if (opt & OPT_S) {
 909                openlog(applet_name, LOG_PID, LOG_DAEMON);
 910                logmode |= LOGMODE_SYSLOG;
 911        }
 912        if (opt & OPT_I) {
 913                len_and_sockaddr *lsa = xhost_and_af2sockaddr(str_I, 0, AF_INET);
 914                server_data.server_nip = lsa->u.sin.sin_addr.s_addr;
 915                free(lsa);
 916        }
 917#if ENABLE_FEATURE_UDHCP_PORT
 918        if (opt & OPT_P) {
 919                SERVER_PORT = xatou16(str_P);
 920                CLIENT_PORT = SERVER_PORT + 1;
 921        }
 922#endif
 923        arpping_ms = xatou(str_a);
 924
 925        /* Would rather not do read_config before daemonization -
 926         * otherwise NOMMU machines will parse config twice */
 927        read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
 928        /* prevent poll timeout overflow */
 929        if (server_data.auto_time > INT_MAX / 1000)
 930                server_data.auto_time = INT_MAX / 1000;
 931
 932        /* Create pidfile */
 933        write_pidfile(server_data.pidfile);
 934        /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */
 935
 936        bb_simple_info_msg("started, v"BB_VER);
 937
 938        option = udhcp_find_option(server_data.options, DHCP_LEASE_TIME, /*dhcpv6:*/ 0);
 939        server_data.max_lease_sec = DEFAULT_LEASE_TIME;
 940        if (option) {
 941                move_from_unaligned32(server_data.max_lease_sec, option->data + OPT_DATA);
 942                server_data.max_lease_sec = ntohl(server_data.max_lease_sec);
 943        }
 944
 945        /* Sanity check */
 946        num_ips = server_data.end_ip - server_data.start_ip + 1;
 947        if (server_data.max_leases > num_ips) {
 948                bb_error_msg("max_leases=%u is too big, setting to %u",
 949                        (unsigned)server_data.max_leases, num_ips);
 950                server_data.max_leases = num_ips;
 951        }
 952
 953        /* this sets g_leases */
 954        SET_PTR_TO_GLOBALS(xzalloc(server_data.max_leases * sizeof(g_leases[0])));
 955
 956        read_leases(server_data.lease_file);
 957
 958        if (udhcp_read_interface(server_data.interface,
 959                        &server_data.ifindex,
 960                        (server_data.server_nip == 0 ? &server_data.server_nip : NULL),
 961                        server_data.server_mac)
 962        ) {
 963                retval = 1;
 964                goto ret;
 965        }
 966
 967 continue_with_autotime:
 968        timeout_end = monotonic_sec() + server_data.auto_time;
 969        while (1) { /* loop until universe collapses */
 970                struct pollfd pfds[2];
 971                struct dhcp_packet packet;
 972                int bytes;
 973                int tv;
 974                uint8_t *msg_type;
 975                uint8_t *server_id_opt;
 976                uint8_t *requested_ip_opt;
 977                uint32_t requested_nip;
 978                uint32_t static_lease_nip;
 979                struct dyn_lease *lease, fake_lease;
 980
 981                if (server_socket < 0) {
 982                        server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
 983                                        server_data.interface);
 984                }
 985
 986                udhcp_sp_fd_set(pfds, server_socket);
 987
 988 new_tv:
 989                tv = -1;
 990                if (server_data.auto_time) {
 991                        tv = timeout_end - monotonic_sec();
 992                        if (tv <= 0) {
 993 write_leases:
 994                                write_leases();
 995                                goto continue_with_autotime;
 996                        }
 997                        tv *= 1000;
 998                }
 999
1000                /* Block here waiting for either signal or packet */
1001                retval = poll(pfds, 2, tv);
1002                if (retval <= 0) {
1003                        if (retval == 0)
1004                                goto write_leases;
1005                        if (errno == EINTR)
1006                                goto new_tv;
1007                        /* < 0 and not EINTR: should not happen */
1008                        bb_simple_perror_msg_and_die("poll");
1009                }
1010
1011                if (pfds[0].revents) switch (udhcp_sp_read()) {
1012                case SIGUSR1:
1013                        bb_info_msg("received %s", "SIGUSR1");
1014                        write_leases();
1015                        /* why not just reset the timeout, eh */
1016                        goto continue_with_autotime;
1017                case SIGTERM:
1018                        bb_info_msg("received %s", "SIGTERM");
1019                        write_leases();
1020                        goto ret0;
1021                }
1022
1023                /* Is it a packet? */
1024                if (!pfds[1].revents)
1025                        continue; /* no */
1026
1027                /* Note: we do not block here, we block on poll() instead.
1028                 * Blocking here would prevent SIGTERM from working:
1029                 * socket read inside this call is restarted on caught signals.
1030                 */
1031                bytes = udhcp_recv_kernel_packet(&packet, server_socket);
1032//NB: we do not check source port here. Should we?
1033//It should be CLIENT_PORT for clients,
1034//or SERVER_PORT for relay agents (in which case giaddr must be != 0.0.0.0)
1035                if (bytes < 0) {
1036                        /* bytes can also be -2 ("bad packet data") */
1037                        if (bytes == -1 && errno != EINTR) {
1038                                log1("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO);
1039                                close(server_socket);
1040                                server_socket = -1;
1041                        }
1042                        continue;
1043                }
1044                if (packet.hlen != 6) {
1045                        bb_info_msg("MAC length != 6%s", ", ignoring packet");
1046                        continue;
1047                }
1048                if (packet.op != BOOTREQUEST) {
1049                        bb_info_msg("not a REQUEST%s", ", ignoring packet");
1050                        continue;
1051                }
1052                msg_type = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
1053                if (!msg_type || msg_type[0] < DHCP_MINTYPE || msg_type[0] > DHCP_MAXTYPE) {
1054                        bb_info_msg("no or bad message type option%s", ", ignoring packet");
1055                        continue;
1056                }
1057
1058                /* Get SERVER_ID if present */
1059                server_id_opt = udhcp_get_option32(&packet, DHCP_SERVER_ID);
1060                if (server_id_opt) {
1061                        uint32_t server_id_network_order;
1062                        move_from_unaligned32(server_id_network_order, server_id_opt);
1063                        if (server_id_network_order != server_data.server_nip) {
1064                                /* client talks to somebody else */
1065                                log1("server ID doesn't match%s", ", ignoring packet");
1066                                continue;
1067                        }
1068                }
1069
1070                /* Look for a static/dynamic lease */
1071                static_lease_nip = get_static_nip_by_mac(&packet.chaddr);
1072                if (static_lease_nip) {
1073                        bb_info_msg("found static lease: %x", static_lease_nip);
1074                        memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
1075                        fake_lease.lease_nip = static_lease_nip;
1076                        fake_lease.expires = 0;
1077                        lease = &fake_lease;
1078                } else {
1079                        lease = find_lease_by_mac(packet.chaddr);
1080                }
1081
1082                /* Get REQUESTED_IP if present */
1083                requested_nip = 0;
1084                requested_ip_opt = udhcp_get_option32(&packet, DHCP_REQUESTED_IP);
1085                if (requested_ip_opt) {
1086                        move_from_unaligned32(requested_nip, requested_ip_opt);
1087                }
1088
1089                switch (msg_type[0]) {
1090
1091                case DHCPDISCOVER:
1092                        log1("received %s", "DISCOVER");
1093
1094                        send_offer(&packet, static_lease_nip, lease, requested_nip, arpping_ms);
1095                        break;
1096
1097                case DHCPREQUEST:
1098                        log1("received %s", "REQUEST");
1099/* RFC 2131:
1100
1101o DHCPREQUEST generated during SELECTING state:
1102
1103   Client inserts the address of the selected server in 'server
1104   identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
1105   filled in with the yiaddr value from the chosen DHCPOFFER.
1106
1107   Note that the client may choose to collect several DHCPOFFER
1108   messages and select the "best" offer.  The client indicates its
1109   selection by identifying the offering server in the DHCPREQUEST
1110   message.  If the client receives no acceptable offers, the client
1111   may choose to try another DHCPDISCOVER message.  Therefore, the
1112   servers may not receive a specific DHCPREQUEST from which they can
1113   decide whether or not the client has accepted the offer.
1114
1115o DHCPREQUEST generated during INIT-REBOOT state:
1116
1117   'server identifier' MUST NOT be filled in, 'requested IP address'
1118   option MUST be filled in with client's notion of its previously
1119   assigned address. 'ciaddr' MUST be zero. The client is seeking to
1120   verify a previously allocated, cached configuration. Server SHOULD
1121   send a DHCPNAK message to the client if the 'requested IP address'
1122   is incorrect, or is on the wrong network.
1123
1124   Determining whether a client in the INIT-REBOOT state is on the
1125   correct network is done by examining the contents of 'giaddr', the
1126   'requested IP address' option, and a database lookup. If the DHCP
1127   server detects that the client is on the wrong net (i.e., the
1128   result of applying the local subnet mask or remote subnet mask (if
1129   'giaddr' is not zero) to 'requested IP address' option value
1130   doesn't match reality), then the server SHOULD send a DHCPNAK
1131   message to the client.
1132
1133   If the network is correct, then the DHCP server should check if
1134   the client's notion of its IP address is correct. If not, then the
1135   server SHOULD send a DHCPNAK message to the client. If the DHCP
1136   server has no record of this client, then it MUST remain silent,
1137   and MAY output a warning to the network administrator. This
1138   behavior is necessary for peaceful coexistence of non-
1139   communicating DHCP servers on the same wire.
1140
1141   If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on
1142   the same subnet as the server.  The server MUST broadcast the
1143   DHCPNAK message to the 0xffffffff broadcast address because the
1144   client may not have a correct network address or subnet mask, and
1145   the client may not be answering ARP requests.
1146
1147   If 'giaddr' is set in the DHCPREQUEST message, the client is on a
1148   different subnet.  The server MUST set the broadcast bit in the
1149   DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
1150   client, because the client may not have a correct network address
1151   or subnet mask, and the client may not be answering ARP requests.
1152
1153o DHCPREQUEST generated during RENEWING state:
1154
1155   'server identifier' MUST NOT be filled in, 'requested IP address'
1156   option MUST NOT be filled in, 'ciaddr' MUST be filled in with
1157   client's IP address. In this situation, the client is completely
1158   configured, and is trying to extend its lease. This message will
1159   be unicast, so no relay agents will be involved in its
1160   transmission.  Because 'giaddr' is therefore not filled in, the
1161   DHCP server will trust the value in 'ciaddr', and use it when
1162   replying to the client.
1163
1164   A client MAY choose to renew or extend its lease prior to T1.  The
1165   server may choose not to extend the lease (as a policy decision by
1166   the network administrator), but should return a DHCPACK message
1167   regardless.
1168
1169o DHCPREQUEST generated during REBINDING state:
1170
1171   'server identifier' MUST NOT be filled in, 'requested IP address'
1172   option MUST NOT be filled in, 'ciaddr' MUST be filled in with
1173   client's IP address. In this situation, the client is completely
1174   configured, and is trying to extend its lease. This message MUST
1175   be broadcast to the 0xffffffff IP broadcast address.  The DHCP
1176   server SHOULD check 'ciaddr' for correctness before replying to
1177   the DHCPREQUEST.
1178
1179   The DHCPREQUEST from a REBINDING client is intended to accommodate
1180   sites that have multiple DHCP servers and a mechanism for
1181   maintaining consistency among leases managed by multiple servers.
1182   A DHCP server MAY extend a client's lease only if it has local
1183   administrative authority to do so.
1184*/
1185                        if (!requested_ip_opt) {
1186                                requested_nip = packet.ciaddr;
1187                                if (requested_nip == 0) {
1188                                        log1("no requested IP and no ciaddr%s", ", ignoring packet");
1189                                        break;
1190                                }
1191                        }
1192                        if (lease && requested_nip == lease->lease_nip) {
1193                                /* client requested or configured IP matches the lease.
1194                                 * ACK it, and bump lease expiration time. */
1195                                send_ACK(&packet, lease->lease_nip);
1196                                break;
1197                        }
1198                        /* No lease for this MAC, or lease IP != requested IP */
1199
1200                        if (server_id_opt    /* client is in SELECTING state */
1201                         || requested_ip_opt /* client is in INIT-REBOOT state */
1202                        ) {
1203                                /* "No, we don't have this IP for you" */
1204                                send_NAK(&packet);
1205                        } /* else: client is in RENEWING or REBINDING, do not answer */
1206
1207                        break;
1208
1209                case DHCPDECLINE:
1210                        /* RFC 2131:
1211                         * "If the server receives a DHCPDECLINE message,
1212                         * the client has discovered through some other means
1213                         * that the suggested network address is already
1214                         * in use. The server MUST mark the network address
1215                         * as not available and SHOULD notify the local
1216                         * sysadmin of a possible configuration problem."
1217                         *
1218                         * SERVER_ID must be present,
1219                         * REQUESTED_IP must be present,
1220                         * chaddr must be filled in,
1221                         * ciaddr must be 0 (we do not check this)
1222                         */
1223                        log1("received %s", "DECLINE");
1224                        if (server_id_opt
1225                         && requested_ip_opt
1226                         && lease  /* chaddr matches this lease */
1227                         && requested_nip == lease->lease_nip
1228                        ) {
1229                                memset(lease->lease_mac, 0, sizeof(lease->lease_mac));
1230                                lease->expires = time(NULL) + server_data.decline_time;
1231                        }
1232                        break;
1233
1234                case DHCPRELEASE:
1235                        /* "Upon receipt of a DHCPRELEASE message, the server
1236                         * marks the network address as not allocated."
1237                         *
1238                         * SERVER_ID must be present,
1239                         * REQUESTED_IP must not be present (we do not check this),
1240                         * chaddr must be filled in,
1241                         * ciaddr must be filled in
1242                         */
1243                        log1("received %s", "RELEASE");
1244                        if (server_id_opt
1245                         && lease  /* chaddr matches this lease */
1246                         && packet.ciaddr == lease->lease_nip
1247                        ) {
1248                                lease->expires = time(NULL);
1249                        }
1250                        break;
1251
1252                case DHCPINFORM:
1253                        log1("received %s", "INFORM");
1254                        send_inform(&packet);
1255                        break;
1256                }
1257        }
1258 ret0:
1259        retval = 0;
1260 ret:
1261        /*if (server_data.pidfile) - server_data.pidfile is never NULL */
1262                remove_pidfile(server_data.pidfile);
1263        return retval;
1264}
1265