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