udhcp: make rfc derived doc more readable (but it still is contradictory)
[oweals/busybox.git] / networking / udhcp / dhcpd.c
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
24 #include <syslog.h>
25 #include "common.h"
26 #include "dhcpc.h"
27 #include "dhcpd.h"
28
29
30 /* Send a packet to a specific mac address and ip address by creating our own ip packet */
31 static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadcast)
32 {
33         const uint8_t *chaddr;
34         uint32_t ciaddr;
35
36         // Was:
37         //if (force_broadcast) { /* broadcast */ }
38         //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
39         //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
40         //else { /* unicast to dhcp_pkt->yiaddr */ }
41         // But this is wrong: yiaddr is _our_ idea what client's IP is
42         // (for example, from lease file). Client may not know that,
43         // and may not have UDP socket listening on that IP!
44         // We should never unicast to dhcp_pkt->yiaddr!
45         // dhcp_pkt->ciaddr, OTOH, comes from client's request packet,
46         // and can be used.
47
48         if (force_broadcast
49          || (dhcp_pkt->flags & htons(BROADCAST_FLAG))
50          || dhcp_pkt->ciaddr == 0
51         ) {
52                 log1("Broadcasting packet to client");
53                 ciaddr = INADDR_BROADCAST;
54                 chaddr = MAC_BCAST_ADDR;
55         } else {
56                 log1("Unicasting packet to client ciaddr");
57                 ciaddr = dhcp_pkt->ciaddr;
58                 chaddr = dhcp_pkt->chaddr;
59         }
60
61         udhcp_send_raw_packet(dhcp_pkt,
62                 /*src*/ server_config.server_nip, SERVER_PORT,
63                 /*dst*/ ciaddr, CLIENT_PORT, chaddr,
64                 server_config.ifindex);
65 }
66
67 /* Send a packet to gateway_nip using the kernel ip stack */
68 static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
69 {
70         log1("Forwarding packet to relay");
71
72         udhcp_send_kernel_packet(dhcp_pkt,
73                         server_config.server_nip, SERVER_PORT,
74                         dhcp_pkt->gateway_nip, SERVER_PORT);
75 }
76
77 static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
78 {
79         if (dhcp_pkt->gateway_nip)
80                 send_packet_to_relay(dhcp_pkt);
81         else
82                 send_packet_to_client(dhcp_pkt, force_broadcast);
83 }
84
85 static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
86 {
87         /* Sets op, htype, hlen, cookie fields
88          * and adds DHCP_MESSAGE_TYPE option */
89         udhcp_init_header(packet, type);
90
91         packet->xid = oldpacket->xid;
92         memcpy(packet->chaddr, oldpacket->chaddr, sizeof(oldpacket->chaddr));
93         packet->flags = oldpacket->flags;
94         packet->gateway_nip = oldpacket->gateway_nip;
95         packet->ciaddr = oldpacket->ciaddr;
96         udhcp_add_simple_option(packet->options, DHCP_SERVER_ID, server_config.server_nip);
97 }
98
99 /* Fill options field, siaddr_nip, and sname and boot_file fields.
100  * TODO: teach this code to use overload option.
101  */
102 static void add_server_options(struct dhcp_packet *packet)
103 {
104         struct option_set *curr = server_config.options;
105
106         while (curr) {
107                 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME)
108                         udhcp_add_option_string(packet->options, curr->data);
109                 curr = curr->next;
110         }
111
112         packet->siaddr_nip = server_config.siaddr_nip;
113
114         if (server_config.sname)
115                 strncpy((char*)packet->sname, server_config.sname, sizeof(packet->sname) - 1);
116         if (server_config.boot_file)
117                 strncpy((char*)packet->file, server_config.boot_file, sizeof(packet->file) - 1);
118 }
119
120 static uint32_t select_lease_time(struct dhcp_packet *packet)
121 {
122         uint32_t lease_time_sec = server_config.max_lease_sec;
123         uint8_t *lease_time_opt = udhcp_get_option(packet, DHCP_LEASE_TIME);
124         if (lease_time_opt) {
125                 move_from_unaligned32(lease_time_sec, lease_time_opt);
126                 lease_time_sec = ntohl(lease_time_sec);
127                 if (lease_time_sec > server_config.max_lease_sec)
128                         lease_time_sec = server_config.max_lease_sec;
129                 if (lease_time_sec < server_config.min_lease_sec)
130                         lease_time_sec = server_config.min_lease_sec;
131         }
132         return lease_time_sec;
133 }
134
135 /* We got a DHCP DISCOVER. Send an OFFER. */
136 static void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease)
137 {
138         struct dhcp_packet packet;
139         uint32_t lease_time_sec;
140         struct in_addr addr;
141
142         init_packet(&packet, oldpacket, DHCPOFFER);
143
144         /* If it is a static lease, use its IP */
145         packet.yiaddr = static_lease_nip;
146         /* Else: */
147         if (!static_lease_nip) {
148                 /* We have no static lease for client's chaddr */
149                 uint32_t req_nip;
150                 uint8_t *req_ip_opt;
151                 const char *p_host_name;
152
153                 if (lease) {
154                         /* We have a dynamic lease for client's chaddr.
155                          * Reuse its IP (even if lease is expired).
156                          * Note that we ignore requested IP in this case.
157                          */
158                         packet.yiaddr = lease->lease_nip;
159                 }
160                 /* Or: if client has requested an IP */
161                 else if ((req_ip_opt = udhcp_get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL
162                  /* (read IP) */
163                  && (move_from_unaligned32(req_nip, req_ip_opt), 1)
164                  /* and the IP is in the lease range */
165                  && ntohl(req_nip) >= server_config.start_ip
166                  && ntohl(req_nip) <= server_config.end_ip
167                  /* and */
168                  && (  !(lease = find_lease_by_nip(req_nip)) /* is not already taken */
169                     || is_expired_lease(lease) /* or is taken, but expired */
170                     )
171                 ) {
172                         packet.yiaddr = req_nip;
173                 }
174                 else {
175                         /* Otherwise, find a free IP */
176                         packet.yiaddr = find_free_or_expired_nip(oldpacket->chaddr);
177                 }
178
179                 if (!packet.yiaddr) {
180                         bb_error_msg("no free IP addresses. OFFER abandoned");
181                         return;
182                 }
183                 /* Reserve the IP for a short time hoping to get DHCPREQUEST soon */
184                 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
185                 lease = add_lease(packet.chaddr, packet.yiaddr,
186                                 server_config.offer_time,
187                                 p_host_name,
188                                 p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
189                 );
190                 if (!lease) {
191                         bb_error_msg("no free IP addresses. OFFER abandoned");
192                         return;
193                 }
194         }
195
196         lease_time_sec = select_lease_time(oldpacket);
197         udhcp_add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec));
198         add_server_options(&packet);
199
200         addr.s_addr = packet.yiaddr;
201         bb_info_msg("Sending OFFER of %s", inet_ntoa(addr));
202         /* send_packet emits error message itself if it detects failure */
203         send_packet(&packet, /*force_bcast:*/ 0);
204 }
205
206 static void send_NAK(struct dhcp_packet *oldpacket)
207 {
208         struct dhcp_packet packet;
209
210         init_packet(&packet, oldpacket, DHCPNAK);
211
212         log1("Sending NAK");
213         send_packet(&packet, /*force_bcast:*/ 1);
214 }
215
216 static void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
217 {
218         struct dhcp_packet packet;
219         uint32_t lease_time_sec;
220         struct in_addr addr;
221         const char *p_host_name;
222
223         init_packet(&packet, oldpacket, DHCPACK);
224         packet.yiaddr = yiaddr;
225
226         lease_time_sec = select_lease_time(oldpacket);
227         udhcp_add_simple_option(packet.options, DHCP_LEASE_TIME, htonl(lease_time_sec));
228
229         add_server_options(&packet);
230
231         addr.s_addr = yiaddr;
232         bb_info_msg("Sending ACK to %s", inet_ntoa(addr));
233         send_packet(&packet, /*force_bcast:*/ 0);
234
235         p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
236         add_lease(packet.chaddr, packet.yiaddr,
237                 lease_time_sec,
238                 p_host_name,
239                 p_host_name ? (unsigned char)p_host_name[OPT_LEN - OPT_DATA] : 0
240         );
241         if (ENABLE_FEATURE_UDHCPD_WRITE_LEASES_EARLY) {
242                 /* rewrite the file with leases at every new acceptance */
243                 write_leases();
244         }
245 }
246
247 static void send_inform(struct dhcp_packet *oldpacket)
248 {
249         struct dhcp_packet packet;
250
251         /* "The server responds to a DHCPINFORM message by sending a DHCPACK
252          * message directly to the address given in the 'ciaddr' field
253          * of the DHCPINFORM message.  The server MUST NOT send a lease
254          * expiration time to the client and SHOULD NOT fill in 'yiaddr'."
255          */
256         init_packet(&packet, oldpacket, DHCPACK);
257         add_server_options(&packet);
258
259         send_packet(&packet, /*force_bcast:*/ 0);
260 }
261
262
263 /* globals */
264 struct dyn_lease *g_leases;
265 /* struct server_config_t server_config is in bb_common_bufsiz1 */
266
267
268 int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
269 int udhcpd_main(int argc UNUSED_PARAM, char **argv)
270 {
271         fd_set rfds;
272         int server_socket = -1, retval, max_sock;
273         struct dhcp_packet packet;
274         uint8_t *state;
275         uint32_t static_lease_nip;
276         unsigned timeout_end;
277         unsigned num_ips;
278         unsigned opt;
279         struct option_set *option;
280         struct dyn_lease *lease, fake_lease;
281         IF_FEATURE_UDHCP_PORT(char *str_P;)
282
283 #if ENABLE_FEATURE_UDHCP_PORT
284         SERVER_PORT = 67;
285         CLIENT_PORT = 68;
286 #endif
287
288 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
289         opt_complementary = "vv";
290 #endif
291         opt = getopt32(argv, "fSv"
292                 IF_FEATURE_UDHCP_PORT("P:", &str_P)
293 #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
294                 , &dhcp_verbose
295 #endif
296                 );
297         argv += optind;
298         if (!(opt & 1)) { /* no -f */
299                 bb_daemonize_or_rexec(0, argv);
300                 logmode = LOGMODE_NONE;
301         }
302         if (opt & 2) { /* -S */
303                 openlog(applet_name, LOG_PID, LOG_DAEMON);
304                 logmode |= LOGMODE_SYSLOG;
305         }
306 #if ENABLE_FEATURE_UDHCP_PORT
307         if (opt & 4) { /* -P */
308                 SERVER_PORT = xatou16(str_P);
309                 CLIENT_PORT = SERVER_PORT + 1;
310         }
311 #endif
312         /* Would rather not do read_config before daemonization -
313          * otherwise NOMMU machines will parse config twice */
314         read_config(argv[0] ? argv[0] : DHCPD_CONF_FILE);
315
316         /* Make sure fd 0,1,2 are open */
317         bb_sanitize_stdio();
318         /* Equivalent of doing a fflush after every \n */
319         setlinebuf(stdout);
320
321         /* Create pidfile */
322         write_pidfile(server_config.pidfile);
323         /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */
324
325         bb_info_msg("%s (v"BB_VER") started", applet_name);
326
327         option = find_option(server_config.options, DHCP_LEASE_TIME);
328         server_config.max_lease_sec = DEFAULT_LEASE_TIME;
329         if (option) {
330                 move_from_unaligned32(server_config.max_lease_sec, option->data + OPT_DATA);
331                 server_config.max_lease_sec = ntohl(server_config.max_lease_sec);
332         }
333
334         /* Sanity check */
335         num_ips = server_config.end_ip - server_config.start_ip + 1;
336         if (server_config.max_leases > num_ips) {
337                 bb_error_msg("max_leases=%u is too big, setting to %u",
338                         (unsigned)server_config.max_leases, num_ips);
339                 server_config.max_leases = num_ips;
340         }
341
342         g_leases = xzalloc(server_config.max_leases * sizeof(g_leases[0]));
343         read_leases(server_config.lease_file);
344
345         if (udhcp_read_interface(server_config.interface,
346                         &server_config.ifindex,
347                         &server_config.server_nip,
348                         server_config.server_mac)
349         ) {
350                 retval = 1;
351                 goto ret;
352         }
353
354         /* Setup the signal pipe */
355         udhcp_sp_setup();
356
357         timeout_end = monotonic_sec() + server_config.auto_time;
358         while (1) { /* loop until universe collapses */
359                 int bytes;
360                 struct timeval tv;
361                 uint8_t *server_id_opt;
362                 uint8_t *requested_opt;
363                 uint32_t requested_nip = requested_nip; /* for compiler */
364
365                 if (server_socket < 0) {
366                         server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
367                                         server_config.interface);
368                 }
369
370                 max_sock = udhcp_sp_fd_set(&rfds, server_socket);
371                 if (server_config.auto_time) {
372                         tv.tv_sec = timeout_end - monotonic_sec();
373                         tv.tv_usec = 0;
374                 }
375                 retval = 0;
376                 if (!server_config.auto_time || tv.tv_sec > 0) {
377                         retval = select(max_sock + 1, &rfds, NULL, NULL,
378                                         server_config.auto_time ? &tv : NULL);
379                 }
380                 if (retval == 0) {
381                         write_leases();
382                         timeout_end = monotonic_sec() + server_config.auto_time;
383                         continue;
384                 }
385                 if (retval < 0 && errno != EINTR) {
386                         log1("Error on select");
387                         continue;
388                 }
389
390                 switch (udhcp_sp_read(&rfds)) {
391                 case SIGUSR1:
392                         bb_info_msg("Received a SIGUSR1");
393                         write_leases();
394                         /* why not just reset the timeout, eh */
395                         timeout_end = monotonic_sec() + server_config.auto_time;
396                         continue;
397                 case SIGTERM:
398                         bb_info_msg("Received a SIGTERM");
399                         goto ret0;
400                 case 0: /* no signal: read a packet */
401                         break;
402                 default: /* signal or error (probably EINTR): back to select */
403                         continue;
404                 }
405
406                 bytes = udhcp_recv_kernel_packet(&packet, server_socket);
407                 if (bytes < 0) {
408                         /* bytes can also be -2 ("bad packet data") */
409                         if (bytes == -1 && errno != EINTR) {
410                                 log1("Read error: %s, reopening socket", strerror(errno));
411                                 close(server_socket);
412                                 server_socket = -1;
413                         }
414                         continue;
415                 }
416                 if (packet.hlen != 6) {
417                         bb_error_msg("MAC length != 6, ignoring packet");
418                         continue;
419                 }
420                 if (packet.op != BOOTREQUEST) {
421                         bb_error_msg("not a REQUEST, ignoring packet");
422                         continue;
423                 }
424                 state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
425                 if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) {
426                         bb_error_msg("no or bad message type option, ignoring packet");
427                         continue;
428                 }
429
430                 /* Look for a static/dynamic lease */
431                 static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr);
432                 if (static_lease_nip) {
433                         bb_info_msg("Found static lease: %x", static_lease_nip);
434                         memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
435                         fake_lease.lease_nip = static_lease_nip;
436                         fake_lease.expires = 0;
437                         lease = &fake_lease;
438                 } else {
439                         lease = find_lease_by_mac(packet.chaddr);
440                 }
441
442                 /* Get REQUESTED_IP and SERVER_ID if present */
443                 server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID);
444                 if (server_id_opt) {
445                         uint32_t server_id_net;
446                         move_from_unaligned32(server_id_net, server_id_opt);
447                         if (server_id_net != server_config.server_nip) {
448                                 /* client talks to somebody else */
449                                 log1("server ID doesn't match, ignoring");
450                                 continue;
451                         }
452                 }
453                 requested_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP);
454                 if (requested_opt) {
455                         move_from_unaligned32(requested_nip, requested_opt);
456                 }
457
458                 switch (state[0]) {
459
460                 case DHCPDISCOVER:
461                         log1("Received DISCOVER");
462
463                         send_offer(&packet, static_lease_nip, lease);
464                         break;
465
466                 case DHCPREQUEST:
467                         log1("Received REQUEST");
468 /* RFC 2131:
469
470 o DHCPREQUEST generated during SELECTING state:
471
472    Client inserts the address of the selected server in 'server
473    identifier', 'ciaddr' MUST be zero, 'requested IP address' MUST be
474    filled in with the yiaddr value from the chosen DHCPOFFER.
475
476    Note that the client may choose to collect several DHCPOFFER
477    messages and select the "best" offer.  The client indicates its
478    selection by identifying the offering server in the DHCPREQUEST
479    message.  If the client receives no acceptable offers, the client
480    may choose to try another DHCPDISCOVER message.  Therefore, the
481    servers may not receive a specific DHCPREQUEST from which they can
482    decide whether or not the client has accepted the offer.
483
484 o DHCPREQUEST generated during INIT-REBOOT state:
485
486    'server identifier' MUST NOT be filled in, 'requested IP address'
487    option MUST be filled in with client's notion of its previously
488    assigned address. 'ciaddr' MUST be zero. The client is seeking to
489    verify a previously allocated, cached configuration. Server SHOULD
490    send a DHCPNAK message to the client if the 'requested IP address'
491    is incorrect, or is on the wrong network.
492
493    Determining whether a client in the INIT-REBOOT state is on the
494    correct network is done by examining the contents of 'giaddr', the
495    'requested IP address' option, and a database lookup. If the DHCP
496    server detects that the client is on the wrong net (i.e., the
497    result of applying the local subnet mask or remote subnet mask (if
498    'giaddr' is not zero) to 'requested IP address' option value
499    doesn't match reality), then the server SHOULD send a DHCPNAK
500    message to the client.
501
502    If the network is correct, then the DHCP server should check if
503    the client's notion of its IP address is correct. If not, then the
504    server SHOULD send a DHCPNAK message to the client. If the DHCP
505    server has no record of this client, then it MUST remain silent,
506    and MAY output a warning to the network administrator. This
507    behavior is necessary for peaceful coexistence of non-
508    communicating DHCP servers on the same wire.
509
510    If 'giaddr' is 0x0 in the DHCPREQUEST message, the client is on
511    the same subnet as the server.  The server MUST broadcast the
512    DHCPNAK message to the 0xffffffff broadcast address because the
513    client may not have a correct network address or subnet mask, and
514    the client may not be answering ARP requests.
515
516    If 'giaddr' is set in the DHCPREQUEST message, the client is on a
517    different subnet.  The server MUST set the broadcast bit in the
518    DHCPNAK, so that the relay agent will broadcast the DHCPNAK to the
519    client, because the client may not have a correct network address
520    or subnet mask, and the client may not be answering ARP requests.
521
522 o DHCPREQUEST generated during RENEWING state:
523
524    'server identifier' MUST NOT be filled in, 'requested IP address'
525    option MUST NOT be filled in, 'ciaddr' MUST be filled in with
526    client's IP address. In this situation, the client is completely
527    configured, and is trying to extend its lease. This message will
528    be unicast, so no relay agents will be involved in its
529    transmission.  Because 'giaddr' is therefore not filled in, the
530    DHCP server will trust the value in 'ciaddr', and use it when
531    replying to the client.
532
533    A client MAY choose to renew or extend its lease prior to T1.  The
534    server may choose not to extend the lease (as a policy decision by
535    the network administrator), but should return a DHCPACK message
536    regardless.
537
538 o DHCPREQUEST generated during REBINDING state:
539
540    'server identifier' MUST NOT be filled in, 'requested IP address'
541    option MUST NOT be filled in, 'ciaddr' MUST be filled in with
542    client's IP address. In this situation, the client is completely
543    configured, and is trying to extend its lease. This message MUST
544    be broadcast to the 0xffffffff IP broadcast address.  The DHCP
545    server SHOULD check 'ciaddr' for correctness before replying to
546    the DHCPREQUEST.
547
548    The DHCPREQUEST from a REBINDING client is intended to accommodate
549    sites that have multiple DHCP servers and a mechanism for
550    maintaining consistency among leases managed by multiple servers.
551    A DHCP server MAY extend a client's lease only if it has local
552    administrative authority to do so.
553 */
554                         if (!requested_opt) {
555                                 requested_nip = packet.ciaddr;
556                                 if (requested_nip == 0) {
557                                         log1("no requested IP and no ciaddr, ignoring");
558                                         break;
559                                 }
560                         }
561                         if (lease && requested_nip == lease->lease_nip) {
562                                 /* client requested or configured IP matches the lease.
563                                  * ACK it, and bump lease expiration time. */
564                                 send_ACK(&packet, lease->lease_nip);
565                                 break;
566                         }
567                         if (server_id_opt) {
568                                 /* client was talking specifically to us.
569                                  * "No, we don't have this IP for you". */
570                                 send_NAK(&packet);
571                         }
572                         break;
573
574                 case DHCPDECLINE:
575                         /* RFC 2131:
576                          * "If the server receives a DHCPDECLINE message,
577                          * the client has discovered through some other means
578                          * that the suggested network address is already
579                          * in use. The server MUST mark the network address
580                          * as not available and SHOULD notify the local
581                          * sysadmin of a possible configuration problem."
582                          *
583                          * SERVER_ID must be present,
584                          * REQUESTED_IP must be present,
585                          * chaddr must be filled in,
586                          * ciaddr must be 0 (we do not check this)
587                          */
588                         log1("Received DECLINE");
589                         if (server_id_opt
590                          && requested_opt
591                          && lease  /* chaddr matches this lease */
592                          && requested_nip == lease->lease_nip
593                         ) {
594                                 memset(lease->lease_mac, 0, sizeof(lease->lease_mac));
595                                 lease->expires = time(NULL) + server_config.decline_time;
596                         }
597                         break;
598
599                 case DHCPRELEASE:
600                         /* "Upon receipt of a DHCPRELEASE message, the server
601                          * marks the network address as not allocated."
602                          *
603                          * SERVER_ID must be present,
604                          * REQUESTED_IP must not be present (we do not check this),
605                          * chaddr must be filled in,
606                          * ciaddr must be filled in
607                          */
608                         log1("Received RELEASE");
609                         if (server_id_opt
610                          && lease  /* chaddr matches this lease */
611                          && packet.ciaddr == lease->lease_nip
612                         ) {
613                                 lease->expires = time(NULL);
614                         }
615                         break;
616
617                 case DHCPINFORM:
618                         log1("Received INFORM");
619                         send_inform(&packet);
620                         break;
621                 }
622         }
623  ret0:
624         retval = 0;
625  ret:
626         /*if (server_config.pidfile) - server_config.pidfile is never NULL */
627                 remove_pidfile(server_config.pidfile);
628         return retval;
629 }