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