xref: /netbsd/external/mpl/dhcp/dist/common/discover.c (revision 13df4856)
1 /*	$NetBSD: discover.c,v 1.5 2022/04/03 01:10:58 christos Exp $	*/
2 
3 /* discover.c
4 
5    Find and identify the network interfaces. */
6 
7 /*
8  * Copyright (C) 2004-2022 Internet Systems Consortium, Inc. ("ISC")
9  * Copyright (c) 1995-2003 by Internet Software Consortium
10  *
11  * This Source Code Form is subject to the terms of the Mozilla Public
12  * License, v. 2.0. If a copy of the MPL was not distributed with this
13  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
18  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22  *
23  *   Internet Systems Consortium, Inc.
24  *   PO Box 360
25  *   Newmarket, NH 03857 USA
26  *   <info@isc.org>
27  *   https://www.isc.org/
28  *
29  */
30 
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: discover.c,v 1.5 2022/04/03 01:10:58 christos Exp $");
33 
34 #include "dhcpd.h"
35 
36 /* length of line we can read from the IF file, 256 is too small in some cases */
37 #define IF_LINE_LENGTH 1024
38 
39 #define BSD_COMP		/* needed on Solaris for SIOCGLIFNUM */
40 #include <sys/ioctl.h>
41 #include <errno.h>
42 
43 #ifdef HAVE_NET_IF6_H
44 # include <net/if6.h>
45 #endif
46 
47 struct interface_info *interfaces = 0;
48 struct interface_info *dummy_interfaces = 0;
49 struct interface_info *fallback_interface = 0;
50 
51 int interfaces_invalidated;
52 int quiet_interface_discovery;
53 u_int16_t local_port = 0;
54 u_int16_t remote_port = 0;
55 u_int16_t relay_port = 0;
56 int dhcpv4_over_dhcpv6 = 0;
57 int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
58 int (*dhcp_interface_discovery_hook) (struct interface_info *);
59 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
60 int (*dhcp_interface_shutdown_hook) (struct interface_info *);
61 
62 struct in_addr limited_broadcast;
63 
64 int local_family = AF_INET;
65 struct in_addr local_address;
66 
67 #ifdef DHCPv6
68 /*
69  * Another clear abuse of the fact that undefined IP addresses are all zeroes.
70  */
71 struct in6_addr local_address6;
72 int bind_local_address6 = 0;
73 #endif /* DHCPv6 */
74 
75 void (*bootp_packet_handler) (struct interface_info *,
76 			      struct dhcp_packet *, unsigned,
77 			      unsigned int,
78 			      struct iaddr, struct hardware *);
79 
80 #ifdef DHCPv6
81 void (*dhcpv6_packet_handler)(struct interface_info *,
82 			      const char *, int,
83 			      int, const struct iaddr *,
84 			      isc_boolean_t);
85 #endif /* DHCPv6 */
86 
87 
88 omapi_object_type_t *dhcp_type_interface;
89 #if defined (TRACING)
90 trace_type_t *interface_trace;
91 trace_type_t *inpacket_trace;
92 trace_type_t *outpacket_trace;
93 #endif
94 struct interface_info **interface_vector;
95 int interface_count;
96 int interface_max;
97 
OMAPI_OBJECT_ALLOC(interface,struct interface_info,dhcp_type_interface)98 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
99 
100 isc_result_t interface_setup ()
101 {
102 	isc_result_t status;
103 	status = omapi_object_type_register (&dhcp_type_interface,
104 					     "interface",
105 					     dhcp_interface_set_value,
106 					     dhcp_interface_get_value,
107 					     dhcp_interface_destroy,
108 					     dhcp_interface_signal_handler,
109 					     dhcp_interface_stuff_values,
110 					     dhcp_interface_lookup,
111 					     dhcp_interface_create,
112 					     dhcp_interface_remove,
113 					     0, 0, 0,
114 					     sizeof (struct interface_info),
115 					     interface_initialize, RC_MISC);
116 	if (status != ISC_R_SUCCESS)
117 		log_fatal ("Can't register interface object type: %s",
118 			   isc_result_totext (status));
119 
120 	return status;
121 }
122 
123 #if defined (TRACING)
interface_trace_setup()124 void interface_trace_setup ()
125 {
126 	interface_trace = trace_type_register ("interface", (void *)0,
127 					       trace_interface_input,
128 					       trace_interface_stop, MDL);
129 	inpacket_trace = trace_type_register ("inpacket", (void *)0,
130 					       trace_inpacket_input,
131 					       trace_inpacket_stop, MDL);
132 	outpacket_trace = trace_type_register ("outpacket", (void *)0,
133 					       trace_outpacket_input,
134 					       trace_outpacket_stop, MDL);
135 }
136 #endif
137 
interface_initialize(omapi_object_t * ipo,const char * file,int line)138 isc_result_t interface_initialize (omapi_object_t *ipo,
139 				   const char *file, int line)
140 {
141 	struct interface_info *ip = (struct interface_info *)ipo;
142 	ip -> rfdesc = ip -> wfdesc = -1;
143 	return ISC_R_SUCCESS;
144 }
145 
146 
147 /*
148  * Scanning for Interfaces
149  * -----------------------
150  *
151  * To find interfaces, we create an iterator that abstracts out most
152  * of the platform specifics. Use is fairly straightforward:
153  *
154  * - begin_iface_scan() starts the process.
155  * - Use next_iface() until it returns 0.
156  * - end_iface_scan() performs any necessary cleanup.
157  *
158  * We check for errors on each call to next_iface(), which returns a
159  * description of the error as a string if any occurs.
160  *
161  * We currently have code for Solaris and Linux. Other systems need
162  * to have code written.
163  *
164  * NOTE: the long-term goal is to use the interface code from BIND 9.
165  */
166 
167 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && defined(SIOCGLIFFLAGS)
168 
169 /* HP/UX doesn't define struct lifconf, instead they define struct
170  * if_laddrconf.  Similarly, 'struct lifreq' and 'struct lifaddrreq'.
171  */
172 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
173 # define lifc_len iflc_len
174 # define lifc_buf iflc_buf
175 # define lifc_req iflc_req
176 # define LIFCONF if_laddrconf
177 #else
178 # define ISC_HAVE_LIFC_FAMILY 1
179 # define ISC_HAVE_LIFC_FLAGS 1
180 # define LIFCONF lifconf
181 #endif
182 
183 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
184 # define lifr_addr iflr_addr
185 # define lifr_name iflr_name
186 # define lifr_dstaddr iflr_dstaddr
187 # define lifr_flags iflr_flags
188 # define sockaddr_storage sockaddr_ext
189 # define ss_family sa_family
190 # define LIFREQ if_laddrreq
191 #else
192 # define LIFREQ lifreq
193 #endif
194 
195 #ifndef IF_NAMESIZE
196 # if defined(LIFNAMSIZ)
197 #  define IF_NAMESIZE	LIFNAMSIZ
198 # elif defined(IFNAMSIZ)
199 #  define IF_NAMESIZE	IFNAMSIZ
200 # else
201 #  define IF_NAMESIZE	16
202 # endif
203 #endif
204 #elif !defined(__linux) && !defined(HAVE_IFADDRS_H)
205 # define SIOCGLIFCONF SIOCGIFCONF
206 # define SIOCGLIFFLAGS SIOCGIFFLAGS
207 # define LIFREQ ifreq
208 # define LIFCONF ifconf
209 # define lifr_name ifr_name
210 # define lifr_addr ifr_addr
211 # define lifr_flags ifr_flags
212 # define lifc_len ifc_len
213 # define lifc_buf ifc_buf
214 # define lifc_req ifc_req
215 #ifdef _AIX
216 # define ss_family __ss_family
217 #endif
218 #endif
219 
220 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
221 /*
222  * Solaris support
223  * ---------------
224  *
225  * The SIOCGLIFCONF ioctl() are the extension that you need to use
226  * on Solaris to get information about IPv6 addresses.
227  *
228  * Solaris' extended interface is documented in the if_tcp man page.
229  */
230 
231 /*
232  * Structure holding state about the scan.
233  */
234 struct iface_conf_list {
235 	int sock;		/* file descriptor used to get information */
236 	int num;		/* total number of interfaces */
237 	struct LIFCONF conf;	/* structure used to get information */
238 	int next;		/* next interface to retrieve when iterating */
239 };
240 
241 /*
242  * Structure used to return information about a specific interface.
243  */
244 struct iface_info {
245 	char name[IF_NAMESIZE+1];	/* name of the interface, e.g. "bge0" */
246 	struct sockaddr_storage addr;	/* address information */
247 	isc_uint64_t flags;		/* interface flags, e.g. IFF_LOOPBACK */
248 };
249 
250 /*
251  * Start a scan of interfaces.
252  *
253  * The iface_conf_list structure maintains state for this process.
254  */
255 static int
begin_iface_scan(struct iface_conf_list * ifaces)256 begin_iface_scan(struct iface_conf_list *ifaces) {
257 #ifdef ISC_PLATFORM_HAVELIFNUM
258 	struct lifnum lifnum;
259 #else
260 	int lifnum;
261 #endif
262 
263 	ifaces->sock = socket(local_family, SOCK_DGRAM, IPPROTO_UDP);
264 	if (ifaces->sock < 0) {
265 		log_error("Error creating socket to list interfaces; %m");
266 		return 0;
267 	}
268 
269 	memset(&lifnum, 0, sizeof(lifnum));
270 #ifdef ISC_PLATFORM_HAVELIFNUM
271 	lifnum.lifn_family = AF_UNSPEC;
272 #endif
273 #ifdef SIOCGLIFNUM
274 	if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) {
275 		log_error("Error finding total number of interfaces; %m");
276 		close(ifaces->sock);
277 		ifaces->sock = -1;
278 		return 0;
279 	}
280 
281 #ifdef ISC_PLATFORM_HAVELIFNUM
282 	ifaces->num = lifnum.lifn_count;
283 #else
284 	ifaces->num = lifnum;
285 #endif
286 #else
287 	ifaces->num = 64;
288 #endif /* SIOCGLIFNUM */
289 
290 	memset(&ifaces->conf, 0, sizeof(ifaces->conf));
291 #ifdef ISC_HAVE_LIFC_FAMILY
292 	ifaces->conf.lifc_family = AF_UNSPEC;
293 #endif
294 	ifaces->conf.lifc_len = ifaces->num * sizeof(struct LIFREQ);
295 	ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL);
296 	if (ifaces->conf.lifc_buf == NULL) {
297 		log_fatal("Out of memory getting interface list.");
298 	}
299 
300 	if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) {
301 		log_error("Error getting interfaces configuration list; %m");
302 		dfree(ifaces->conf.lifc_buf, MDL);
303 		close(ifaces->sock);
304 		ifaces->sock = -1;
305 		return 0;
306 	}
307 
308 	ifaces->next = 0;
309 
310 	return 1;
311 }
312 
313 /*
314  * Retrieve the next interface.
315  *
316  * Returns information in the info structure.
317  * Sets err to 1 if there is an error, otherwise 0.
318  */
319 static int
next_iface(struct iface_info * info,int * err,struct iface_conf_list * ifaces)320 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
321 	struct LIFREQ *p;
322 	struct LIFREQ tmp;
323 	isc_boolean_t foundif;
324 #if defined(sun) || defined(__linux)
325 	/* Pointer used to remove interface aliases. */
326 	char *s;
327 #endif
328 
329 	do {
330 		foundif = ISC_FALSE;
331 
332 		if (ifaces->next >= ifaces->num) {
333 			*err = 0;
334 			return 0;
335 		}
336 
337 		p = ifaces->conf.lifc_req;
338 		p += ifaces->next;
339 
340 		if (strlen(p->lifr_name) >= sizeof(info->name)) {
341 			*err = 1;
342 			log_error("Interface name '%s' too long", p->lifr_name);
343 			return 0;
344 		}
345 
346 		/* Reject if interface address family does not match */
347 		if (p->lifr_addr.ss_family != local_family) {
348 			ifaces->next++;
349 			continue;
350 		}
351 
352 		memset(info, 0, sizeof(struct iface_info));
353 		strncpy(info->name, p->lifr_name, sizeof(info->name) - 1);
354 		memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr));
355 
356 #if defined(sun) || defined(__linux)
357 		/* interface aliases look like "eth0:1" or "wlan1:3" */
358 		s = strchr(info->name, ':');
359 		if (s != NULL) {
360 			*s = '\0';
361 		}
362 #endif /* defined(sun) || defined(__linux) */
363 
364 		foundif = ISC_TRUE;
365 	} while ((foundif == ISC_FALSE) ||
366 		 (strncmp(info->name, "dummy", 5) == 0));
367 
368 	memset(&tmp, 0, sizeof(tmp));
369 	strncpy(tmp.lifr_name, info->name, sizeof(tmp.lifr_name) - 1);
370 	if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) {
371 		log_error("Error getting interface flags for '%s'; %m",
372 			  p->lifr_name);
373 		*err = 1;
374 		return 0;
375 	}
376 	info->flags = tmp.lifr_flags;
377 
378 	ifaces->next++;
379 	*err = 0;
380 	return 1;
381 }
382 
383 /*
384  * End scan of interfaces.
385  */
386 static void
end_iface_scan(struct iface_conf_list * ifaces)387 end_iface_scan(struct iface_conf_list *ifaces) {
388 	dfree(ifaces->conf.lifc_buf, MDL);
389 	close(ifaces->sock);
390 	ifaces->sock = -1;
391 }
392 
393 #else
394 
395 /*
396  * BSD/Linux support
397  * -----------
398  *
399  * FreeBSD, NetBSD, OpenBSD, OS X/macOS and Linux all have the getifaddrs()
400  * function.
401  *
402  * The getifaddrs() man page describes the use.
403  */
404 
405 #include <ifaddrs.h>
406 
407 /*
408  * Structure holding state about the scan.
409  */
410 struct iface_conf_list {
411 	struct ifaddrs *head;	/* beginning of the list */
412 	struct ifaddrs *next;	/* current position in the list */
413 };
414 
415 /*
416  * Structure used to return information about a specific interface.
417  */
418 struct iface_info {
419 	char name[IFNAMSIZ];		/* name of the interface, e.g. "bge0" */
420 	struct sockaddr_storage addr;	/* address information */
421 	isc_uint64_t flags;		/* interface flags, e.g. IFF_LOOPBACK */
422 };
423 
424 /*
425  * Start a scan of interfaces.
426  *
427  * The iface_conf_list structure maintains state for this process.
428  */
429 static int
begin_iface_scan(struct iface_conf_list * ifaces)430 begin_iface_scan(struct iface_conf_list *ifaces) {
431 	if (getifaddrs(&ifaces->head) != 0) {
432 		log_error("Error getting interfaces; %m");
433 		return 0;
434 	}
435 	ifaces->next = ifaces->head;
436 	return 1;
437 }
438 
439 /*
440  * Retrieve the next interface.
441  *
442  * Returns information in the info structure.
443  * Sets err to 1 if there is an error, otherwise 0.
444  */
445 static int
next_iface(struct iface_info * info,int * err,struct iface_conf_list * ifaces)446 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
447 	size_t sa_len = 0;
448 
449 	if (ifaces->next == NULL) {
450 		*err = 0;
451 		return 0;
452 	}
453 	if (strlen(ifaces->next->ifa_name) >= sizeof(info->name)) {
454 		log_error("Interface name '%s' too long",
455 			  ifaces->next->ifa_name);
456 		*err = 1;
457 		return 0;
458 	}
459 	memset(info, 0, sizeof(struct iface_info));
460 	strncpy(info->name, ifaces->next->ifa_name, sizeof(info->name) - 1);
461 	memset(&info->addr, 0 , sizeof(info->addr));
462 	/*
463 	 * getifaddrs() can on Linux with some interfaces like PPP or TEQL
464 	 * result in a record with no address (ifa_addr).
465 	 */
466 	if (ifaces->next->ifa_addr != NULL) {
467 /* Linux lacks the sa_len member in struct sockaddr. */
468 #if defined(__linux)
469 		if (ifaces->next->ifa_addr->sa_family == AF_INET)
470 			sa_len = sizeof(struct sockaddr_in);
471 		else if (ifaces->next->ifa_addr->sa_family == AF_INET6)
472 			sa_len = sizeof(struct sockaddr_in6);
473 #else
474 		sa_len = ifaces->next->ifa_addr->sa_len;
475 #endif
476 		memcpy(&info->addr, ifaces->next->ifa_addr, sa_len);
477 	}
478 	info->flags = ifaces->next->ifa_flags;
479 	ifaces->next = ifaces->next->ifa_next;
480 	*err = 0;
481 	return 1;
482 }
483 
484 /*
485  * End scan of interfaces.
486  */
487 static void
end_iface_scan(struct iface_conf_list * ifaces)488 end_iface_scan(struct iface_conf_list *ifaces) {
489 	freeifaddrs(ifaces->head);
490 	ifaces->head = NULL;
491 	ifaces->next = NULL;
492 }
493 #endif
494 
495 /* XXX: perhaps create drealloc() rather than do it manually */
496 static void
add_ipv4_addr_to_interface(struct interface_info * iface,const struct in_addr * addr)497 add_ipv4_addr_to_interface(struct interface_info *iface,
498 			   const struct in_addr *addr) {
499 	/*
500 	 * We don't expect a lot of addresses per IPv4 interface, so
501 	 * we use 4, as our "chunk size" for collecting addresses.
502 	 */
503 	if (iface->addresses == NULL) {
504 		iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL);
505 		if (iface->addresses == NULL) {
506 			log_fatal("Out of memory saving IPv4 address "
507 			          "on interface.");
508 		}
509 		iface->address_count = 0;
510 		iface->address_max = 4;
511 	} else if (iface->address_count >= iface->address_max) {
512 		struct in_addr *tmp;
513 		int new_max;
514 
515 		new_max = iface->address_max + 4;
516 		tmp = dmalloc(new_max * sizeof(struct in_addr), MDL);
517 		if (tmp == NULL) {
518 			log_fatal("Out of memory saving IPv4 address "
519 			          "on interface.");
520 		}
521 		memcpy(tmp,
522 		       iface->addresses,
523 		       iface->address_max * sizeof(struct in_addr));
524 		dfree(iface->addresses, MDL);
525 		iface->addresses = tmp;
526 		iface->address_max = new_max;
527 	}
528 	iface->addresses[iface->address_count++] = *addr;
529 }
530 
531 #ifdef DHCPv6
532 /* XXX: perhaps create drealloc() rather than do it manually */
533 static void
add_ipv6_addr_to_interface(struct interface_info * iface,const struct in6_addr * addr)534 add_ipv6_addr_to_interface(struct interface_info *iface,
535 			   const struct in6_addr *addr) {
536 	/*
537 	 * Each IPv6 interface will have at least two IPv6 addresses,
538 	 * and likely quite a few more. So we use 8, as our "chunk size" for
539 	 * collecting addresses.
540 	 */
541 	if (iface->v6addresses == NULL) {
542 		iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL);
543 		if (iface->v6addresses == NULL) {
544 			log_fatal("Out of memory saving IPv6 address "
545 				  "on interface.");
546 		}
547 		iface->v6address_count = 0;
548 		iface->v6address_max = 8;
549 	} else if (iface->v6address_count >= iface->v6address_max) {
550 		struct in6_addr *tmp;
551 		int new_max;
552 
553 		new_max = iface->v6address_max + 8;
554 		tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL);
555 		if (tmp == NULL) {
556 			log_fatal("Out of memory saving IPv6 address "
557 				  "on interface.");
558 		}
559 		memcpy(tmp,
560 		       iface->v6addresses,
561 		       iface->v6address_max * sizeof(struct in6_addr));
562 		dfree(iface->v6addresses, MDL);
563 		iface->v6addresses = tmp;
564 		iface->v6address_max = new_max;
565 	}
566 	iface->v6addresses[iface->v6address_count++] = *addr;
567 }
568 #endif /* DHCPv6 */
569 
570 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
571    For each interface that's of type INET and not the loopback interface,
572    register that interface with the network I/O software, figure out what
573    subnet it's on, and add it to the list of interfaces. */
574 
575 void
discover_interfaces(int state)576 discover_interfaces(int state) {
577 	struct iface_conf_list ifaces;
578 	struct iface_info info;
579 	int err;
580 
581 	struct interface_info *tmp;
582 	struct interface_info *last, *next;
583 
584 #ifdef DHCPv6
585         char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
586 #endif /* DHCPv6 */
587 
588 
589 	struct subnet *subnet;
590 	int ir;
591 	isc_result_t status;
592 	int wifcount = 0;
593 #ifdef RELAY_PORT
594 	int updone = 0;
595 	int downdone = 0;
596 #endif
597 
598 	static int setup_fallback = 0;
599 
600 	if (!begin_iface_scan(&ifaces)) {
601 		log_fatal("Can't get list of interfaces.");
602 	}
603 
604 	/* If we already have a list of interfaces, and we're running as
605 	   a DHCP server, the interfaces were requested. */
606 	if (interfaces && (state == DISCOVER_SERVER ||
607 			   state == DISCOVER_RELAY ||
608 			   state == DISCOVER_REQUESTED))
609 		ir = 0;
610 	else if (state == DISCOVER_UNCONFIGURED)
611 		ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
612 	else {
613 		ir = INTERFACE_REQUESTED;
614 		if (state == DISCOVER_RELAY && local_family == AF_INET) {
615 			/* We're a v4 relay without specifically requested
616 			 * interfaces, so mark them all as bidirectional. */
617 			ir |= INTERFACE_STREAMS;
618 		}
619 	}
620 
621 	/* Cycle through the list of interfaces looking for IP addresses. */
622 	while (next_iface(&info, &err, &ifaces)) {
623 
624 		/* See if we've seen an interface that matches this one. */
625 		for (tmp = interfaces; tmp; tmp = tmp->next) {
626 			if (!strcmp(tmp->name, info.name))
627 				break;
628 		}
629 
630 		/* Skip non broadcast interfaces (plus loopback and
631 		   point-to-point in case an OS incorrectly marks them
632 		   as broadcast). Also skip down interfaces unless we're
633 		   trying to get a list of configurable interfaces. */
634 		if ((((local_family == AF_INET &&
635 		    !(info.flags & IFF_BROADCAST)) ||
636 #ifdef DHCPv6
637 		    (local_family == AF_INET6 &&
638 		    !(info.flags & IFF_MULTICAST)) ||
639 #endif
640 		      info.flags & IFF_LOOPBACK ||
641 		      info.flags & IFF_POINTOPOINT) && !tmp) ||
642 		    (!(info.flags & IFF_UP) &&
643 		     state != DISCOVER_UNCONFIGURED))
644 			continue;
645 
646 		/* If there isn't already an interface by this name,
647 		   allocate one. */
648 		if (tmp == NULL) {
649 			status = interface_allocate(&tmp, MDL);
650 			if (status != ISC_R_SUCCESS) {
651 				log_fatal("Error allocating interface %s: %s",
652 					  info.name, isc_result_totext(status));
653 			}
654 
655 			memcpy(tmp->name, info.name, sizeof(tmp->name));
656 
657 			interface_snorf(tmp, ir);
658 			interface_dereference(&tmp, MDL);
659 			tmp = interfaces; /* XXX */
660 		}
661 
662 		if (dhcp_interface_discovery_hook) {
663 			(*dhcp_interface_discovery_hook)(tmp);
664 		}
665 
666 		if ((info.addr.ss_family == AF_INET) &&
667 		    (local_family == AF_INET)) {
668 			struct sockaddr_in *a = (struct sockaddr_in*)&info.addr;
669 			struct iaddr addr;
670 
671 			/* We don't want the loopback interface. */
672 			if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) &&
673 			    ((tmp->flags & INTERFACE_AUTOMATIC) &&
674 			     ((state == DISCOVER_SERVER) ||
675 			      (state == DISCOVER_SERVER46))))
676 				continue;
677 
678 			/* If the only address we have is 0.0.0.0, we
679 			   shouldn't consider the interface configured. */
680 			if (a->sin_addr.s_addr != htonl(INADDR_ANY))
681 				tmp->configured = 1;
682 
683 			add_ipv4_addr_to_interface(tmp, &a->sin_addr);
684 
685 			/* invoke the setup hook */
686 			addr.len = 4;
687 			memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len);
688 			if (dhcp_interface_setup_hook) {
689 				(*dhcp_interface_setup_hook)(tmp, &addr);
690 			}
691 		}
692 #ifdef DHCPv6
693 		else if ((info.addr.ss_family == AF_INET6) &&
694 			 (local_family == AF_INET6)) {
695 			struct sockaddr_in6 *a =
696 					(struct sockaddr_in6*)&info.addr;
697 			struct iaddr addr;
698 
699 			/* We don't want the loopback interface. */
700 			if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) &&
701 			    ((tmp->flags & INTERFACE_AUTOMATIC) &&
702 			     ((state == DISCOVER_SERVER) ||
703 			      (state == DISCOVER_SERVER46))))
704 			    continue;
705 
706 			/* If the only address we have is 0.0.0.0, we
707 			   shouldn't consider the interface configured. */
708 			if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
709 				tmp->configured = 1;
710 
711 			add_ipv6_addr_to_interface(tmp, &a->sin6_addr);
712 
713 			/* invoke the setup hook */
714 			addr.len = 16;
715 			memcpy(addr.iabuf, &a->sin6_addr, addr.len);
716 			if (dhcp_interface_setup_hook) {
717 				(*dhcp_interface_setup_hook)(tmp, &addr);
718 			}
719 		}
720 #endif /* DHCPv6 */
721 	}
722 
723 	if (err) {
724 		log_fatal("Error getting interface information.");
725 	}
726 
727 	end_iface_scan(&ifaces);
728 
729 
730 	/* Mock-up an 'ifp' structure which is no longer used in the
731 	 * new interface-sensing code, but is used in higher layers
732 	 * (for example to sense fallback interfaces).
733 	 */
734 	for (tmp = interfaces ; tmp != NULL ; tmp = tmp->next) {
735 		if (tmp->ifp == NULL) {
736 			struct ifreq *tif;
737 
738 			tif = (struct ifreq *)dmalloc(sizeof(struct ifreq),
739 						      MDL);
740 			if (tif == NULL)
741 				log_fatal("no space for ifp mockup.");
742 			strcpy(tif->ifr_name, tmp->name);
743 			tmp->ifp = tif;
744 		}
745 	}
746 
747 
748 	/* If we're just trying to get a list of interfaces that we might
749 	   be able to configure, we can quit now. */
750 	if (state == DISCOVER_UNCONFIGURED) {
751 		return;
752 	}
753 
754 	/* Weed out the interfaces that did not have IP addresses. */
755 	tmp = last = next = NULL;
756 	if (interfaces)
757 		interface_reference (&tmp, interfaces, MDL);
758 	while (tmp) {
759 		if (next)
760 			interface_dereference (&next, MDL);
761 		if (tmp -> next)
762 			interface_reference (&next, tmp -> next, MDL);
763 		/* skip interfaces that are running already */
764 		if (tmp -> flags & INTERFACE_RUNNING) {
765 			interface_dereference(&tmp, MDL);
766 			if(next)
767 				interface_reference(&tmp, next, MDL);
768 			continue;
769 		}
770 		if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
771 		    state == DISCOVER_REQUESTED)
772 			tmp -> flags &= ~(INTERFACE_AUTOMATIC |
773 					  INTERFACE_REQUESTED);
774 
775 #ifdef DHCPv6
776 		if (!(tmp->flags & INTERFACE_REQUESTED)) {
777 #else
778 		if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
779 #endif /* DHCPv6 */
780 			if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
781 				log_fatal ("%s: not found", tmp -> name);
782 			if (!last) {
783 				if (interfaces)
784 					interface_dereference (&interfaces,
785 							       MDL);
786 				if (next)
787 				interface_reference (&interfaces, next, MDL);
788 			} else {
789 				interface_dereference (&last -> next, MDL);
790 				if (next)
791 					interface_reference (&last -> next,
792 							     next, MDL);
793 			}
794 			if (tmp -> next)
795 				interface_dereference (&tmp -> next, MDL);
796 
797 			/* Remember the interface in case we need to know
798 			   about it later. */
799 			if (dummy_interfaces) {
800 				interface_reference (&tmp -> next,
801 						     dummy_interfaces, MDL);
802 				interface_dereference (&dummy_interfaces, MDL);
803 			}
804 			interface_reference (&dummy_interfaces, tmp, MDL);
805 			interface_dereference (&tmp, MDL);
806 			if (next)
807 				interface_reference (&tmp, next, MDL);
808 			continue;
809 		}
810 		last = tmp;
811 
812 		/* We must have a subnet declaration for each interface. */
813 		if (!tmp->shared_network && (state == DISCOVER_SERVER)) {
814 			log_error("%s", "");
815 			if (local_family == AF_INET) {
816 				log_error("No subnet declaration for %s (%s).",
817 					  tmp->name,
818 					  (tmp->addresses == NULL) ?
819 					   "no IPv4 addresses" :
820 					   inet_ntoa(tmp->addresses[0]));
821 #ifdef DHCPv6
822 			} else {
823 				if (tmp->v6addresses != NULL) {
824 					inet_ntop(AF_INET6,
825 						  &tmp->v6addresses[0],
826 						  abuf,
827 						  sizeof(abuf));
828 				} else {
829 					strcpy(abuf, "no IPv6 addresses");
830 				}
831 				log_error("No subnet6 declaration for %s (%s).",
832 					  tmp->name,
833 					  abuf);
834 #endif /* DHCPv6 */
835 			}
836 			if (supports_multiple_interfaces(tmp)) {
837 				log_error ("** Ignoring requests on %s.  %s",
838 					   tmp -> name, "If this is not what");
839 				log_error ("   you want, please write %s",
840 #ifdef DHCPv6
841 				           (local_family != AF_INET) ?
842 					   "a subnet6 declaration" :
843 #endif
844 					   "a subnet declaration");
845 				log_error ("   in your dhcpd.conf file %s",
846 					   "for the network segment");
847 				log_error ("   to %s %s %s",
848 					   "which interface",
849 					   tmp -> name, "is attached. **");
850 				log_error ("%s", "");
851 				goto next;
852 			} else {
853 				log_error ("You must write a %s",
854 #ifdef DHCPv6
855 				           (local_family != AF_INET) ?
856 					   "subnet6 declaration for this" :
857 #endif
858 					   "subnet declaration for this");
859 				log_error ("subnet.   You cannot prevent %s",
860 					   "the DHCP server");
861 				log_error ("from listening on this subnet %s",
862 					   "because your");
863 				log_fatal ("operating system does not %s.",
864 					   "support this capability");
865 			}
866 		}
867 
868 		/* Find subnets that don't have valid interface
869 		   addresses... */
870 		for (subnet = (tmp -> shared_network
871 			       ? tmp -> shared_network -> subnets
872 			       : (struct subnet *)0);
873 		     subnet; subnet = subnet -> next_sibling) {
874 			/* Set the interface address for this subnet
875 			   to the first address we found. */
876 		     	if (subnet->interface_address.len == 0) {
877 				if (tmp->address_count > 0) {
878 					subnet->interface_address.len = 4;
879 					memcpy(subnet->interface_address.iabuf,
880 					       &tmp->addresses[0].s_addr, 4);
881 				} else if (tmp->v6address_count > 0) {
882 					subnet->interface_address.len = 16;
883 					memcpy(subnet->interface_address.iabuf,
884 					       &tmp->v6addresses[0].s6_addr,
885 					       16);
886 				} else {
887 					/* XXX: should be one */
888 					log_error("%s missing an interface "
889 						  "address", tmp->name);
890 					continue;
891 				}
892 			}
893 		}
894 
895 		/* Flag the index as not having been set, so that the
896 		   interface registerer can set it or not as it chooses. */
897 		tmp -> index = -1;
898 
899 		/* Register the interface... */
900 		switch (local_family) {
901 		case AF_INET:
902 			if (!dhcpv4_over_dhcpv6) {
903 				if_register_receive(tmp);
904 				if_register_send(tmp);
905 			} else {
906 				/* get_hw_addr() was called by register. */
907 				get_hw_addr(tmp->name, &tmp->hw_address);
908 			}
909 			break;
910 #ifdef DHCPv6
911 		case AF_INET6:
912 			if ((state == DISCOVER_SERVER) ||
913 			    (state == DISCOVER_RELAY)) {
914 				if_register6(tmp, 1);
915 			} else if (state == DISCOVER_SERVER46) {
916 				/* get_hw_addr() was called by if_register*6
917 				   so now we have to call it explicitly
918 				   to not leave the hardware address unknown
919 				   (some code expects it cannot be. */
920 				get_hw_addr(tmp->name, &tmp->hw_address);
921 			} else {
922 				if_register_linklocal6(tmp);
923 			}
924 			break;
925 #endif /* DHCPv6 */
926 		}
927 
928 		interface_stash (tmp);
929 		wifcount++;
930 #if defined (F_SETFD)
931 		/* if_register*() are no longer always called so
932 		   descriptors  must be checked. */
933 		if ((tmp -> rfdesc >= 0) &&
934 		    (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0))
935 			log_error ("Can't set close-on-exec on %s: %m",
936 				   tmp -> name);
937 		if ((tmp -> wfdesc != tmp -> rfdesc) &&
938 		    (tmp -> wfdesc >= 0) &&
939 		    (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0))
940 			log_error ("Can't set close-on-exec on %s: %m",
941 				   tmp -> name);
942 #endif
943 	      next:
944 		interface_dereference (&tmp, MDL);
945 		if (next)
946 			interface_reference (&tmp, next, MDL);
947 	}
948 
949 	/*
950 	 * Now register all the remaining interfaces as protocols.
951 	 * We register with omapi to allow for control of the interface,
952 	 * we've already registered the fd or socket with the socket
953 	 * manager as part of if_register_receive().
954 	 */
955 	for (tmp = interfaces; tmp; tmp = tmp -> next) {
956 		/* not if it's been registered before */
957 		if (tmp -> flags & INTERFACE_RUNNING)
958 			continue;
959 		if (tmp -> rfdesc == -1)
960 			continue;
961 		switch (local_family) {
962 #ifdef DHCPv6
963 		case AF_INET6:
964 #ifdef RELAY_PORT
965 #define UPSTREAM(ifp) \
966 	((ifp->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM)
967 #define DOWNSTREAM(ifp) \
968         ((ifp->flags & INTERFACE_STREAMS) == INTERFACE_DOWNSTREAM)
969 
970 			if (relay_port) {
971 				/*
972 				 * The normal IPv6 relay only needs one
973 				 * socket as long as we find an interface.
974 				 * When user relay port is defined, and we
975 				 * have two different UDP ports. One to
976 				 * receive from DHCP client with port 547,
977 				 * and the other is user defined for sending
978 				 * to the server or upstream relay agent.
979 				 * Thus we need to register sockets for one
980 				 * upstream and one downstream interfaces.
981 				 */
982 				if (updone && UPSTREAM(tmp))
983 					    continue;
984 				if (downdone && DOWNSTREAM(tmp))
985 					    continue;
986 			}
987 #endif
988 			status = omapi_register_io_object((omapi_object_t *)tmp,
989 							  if_readsocket,
990 							  0, got_one_v6, 0, 0);
991 #ifdef RELAY_PORT
992 			if (UPSTREAM(tmp))
993 				updone++;
994 			else
995 				downdone++;
996 #endif
997 			break;
998 #endif /* DHCPv6 */
999 		case AF_INET:
1000 		default:
1001 			status = omapi_register_io_object((omapi_object_t *)tmp,
1002 							  if_readsocket,
1003 							  0, got_one, 0, 0);
1004 			break;
1005 		}
1006 
1007 		if (status != ISC_R_SUCCESS)
1008 			log_fatal ("Can't register I/O handle for %s: %s",
1009 				   tmp -> name, isc_result_totext (status));
1010 
1011 #if defined(DHCPv6)
1012 		/* Only register the first interface for V6, since
1013 		 * servers and relays all use the same socket.
1014 		 * XXX: This has some messy side effects if we start
1015 		 * dynamically adding and removing interfaces, but
1016 		 * we're well beyond that point in terms of mess.
1017 		 */
1018 		if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY))
1019 		    && (local_family == AF_INET6)
1020 #if defined(RELAY_PORT)
1021 		    && ((relay_port == 0) || (updone && downdone))
1022 #endif
1023 		    )
1024 			break;
1025 #endif
1026 	} /* for (tmp = interfaces; ... */
1027 
1028 	if (state == DISCOVER_SERVER && wifcount == 0) {
1029 		log_info ("%s", "");
1030 		log_fatal ("Not configured to listen on any interfaces!");
1031 	}
1032 
1033 	if ((local_family == AF_INET) &&
1034 	    !setup_fallback && !dhcpv4_over_dhcpv6) {
1035 		setup_fallback = 1;
1036 		maybe_setup_fallback();
1037 	}
1038 
1039 #if defined (F_SETFD)
1040 	if (fallback_interface) {
1041 	    if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
1042 		log_error ("Can't set close-on-exec on fallback: %m");
1043 	    if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
1044 		if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
1045 		    log_error ("Can't set close-on-exec on fallback: %m");
1046 	    }
1047 	}
1048 #endif /* F_SETFD */
1049 }
1050 
1051 int if_readsocket (h)
1052 	omapi_object_t *h;
1053 {
1054 	struct interface_info *ip;
1055 
1056 	if (h -> type != dhcp_type_interface)
1057 		return -1;
1058 	ip = (struct interface_info *)h;
1059 	return ip -> rfdesc;
1060 }
1061 
1062 int setup_fallback (struct interface_info **fp, const char *file, int line)
1063 {
1064 	isc_result_t status;
1065 
1066 	status = interface_allocate (&fallback_interface, file, line);
1067 	if (status != ISC_R_SUCCESS)
1068 		log_fatal ("Error allocating fallback interface: %s",
1069 			   isc_result_totext (status));
1070 	strcpy (fallback_interface -> name, "fallback");
1071 	if (dhcp_interface_setup_hook)
1072 		(*dhcp_interface_setup_hook) (fallback_interface,
1073 					      (struct iaddr *)0);
1074 	status = interface_reference (fp, fallback_interface, file, line);
1075 
1076 	fallback_interface -> index = -1;
1077 	interface_stash (fallback_interface);
1078 	return status == ISC_R_SUCCESS;
1079 }
1080 
1081 void reinitialize_interfaces ()
1082 {
1083 	struct interface_info *ip;
1084 
1085 	for (ip = interfaces; ip; ip = ip -> next) {
1086 		if_reinitialize_receive (ip);
1087 		if_reinitialize_send (ip);
1088 	}
1089 
1090 	if (fallback_interface)
1091 		if_reinitialize_send (fallback_interface);
1092 
1093 	interfaces_invalidated = 1;
1094 }
1095 
1096 isc_result_t got_one (h)
1097 	omapi_object_t *h;
1098 {
1099 	struct sockaddr_in from;
1100 	struct hardware hfrom;
1101 	struct iaddr ifrom;
1102 	int result;
1103 	union {
1104 		unsigned char packbuf [4095]; /* Packet input buffer.
1105 					 	 Must be as large as largest
1106 						 possible MTU. */
1107 		struct dhcp_packet packet;
1108 	} u;
1109 	struct interface_info *ip;
1110 
1111 	if (h -> type != dhcp_type_interface)
1112 		return DHCP_R_INVALIDARG;
1113 	ip = (struct interface_info *)h;
1114 
1115       again:
1116 	if ((result =
1117 	     receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
1118 		log_error ("receive_packet failed on %s: %m", ip -> name);
1119 		return ISC_R_UNEXPECTED;
1120 	}
1121 	if (result == 0)
1122 		return ISC_R_UNEXPECTED;
1123 
1124 	/*
1125 	 * If we didn't at least get the fixed portion of the BOOTP
1126 	 * packet, drop the packet.
1127 	 * Previously we allowed packets with no sname or filename
1128 	 * as we were aware of at least one client that did.  But
1129 	 * a bug caused short packets to not work and nobody has
1130 	 * complained, it seems rational to tighten up that
1131 	 * restriction.
1132 	 */
1133 	if (result < DHCP_FIXED_NON_UDP)
1134 		return ISC_R_UNEXPECTED;
1135 
1136 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
1137 	{
1138 		/* We retrieve the ifindex from the unused hfrom variable */
1139 		unsigned int ifindex;
1140 
1141 		memcpy(&ifindex, hfrom.hbuf, sizeof (ifindex));
1142 
1143 		/*
1144 		 * Seek forward from the first interface to find the matching
1145 		 * source interface by interface index.
1146 		 */
1147 		ip = interfaces;
1148 		while ((ip != NULL) && (if_nametoindex(ip->name) != ifindex))
1149 			ip = ip->next;
1150 		if (ip == NULL)
1151 			return ISC_R_NOTFOUND;
1152 	}
1153 #endif
1154 
1155 	if (bootp_packet_handler) {
1156 		ifrom.len = 4;
1157 		memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
1158 
1159 		(*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
1160 					 from.sin_port, ifrom, &hfrom);
1161 	}
1162 
1163 	/* If there is buffered data, read again.    This is for, e.g.,
1164 	   bpf, which may return two packets at once. */
1165 	if (ip -> rbuf_offset != ip -> rbuf_len)
1166 		goto again;
1167 	return ISC_R_SUCCESS;
1168 }
1169 
1170 #ifdef DHCPv6
1171 isc_result_t
1172 got_one_v6(omapi_object_t *h) {
1173 	struct sockaddr_in6 from;
1174 	struct in6_addr to;
1175 	struct iaddr ifrom;
1176 	int result;
1177 	char buf[65536];	/* maximum size for a UDP packet is 65536 */
1178 	struct interface_info *ip;
1179 	int is_unicast;
1180 	unsigned int if_idx = 0;
1181 
1182 	if (h->type != dhcp_type_interface) {
1183 		return DHCP_R_INVALIDARG;
1184 	}
1185 	ip = (struct interface_info *)h;
1186 
1187 	result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf),
1188 				 &from, &to, &if_idx);
1189 	if (result < 0) {
1190 		log_error("receive_packet6() failed on %s: %m", ip->name);
1191 		return ISC_R_UNEXPECTED;
1192 	}
1193 
1194 	/* 0 is 'any' interface. */
1195 	if (if_idx == 0)
1196 		return ISC_R_NOTFOUND;
1197 
1198 	if (dhcpv6_packet_handler != NULL) {
1199 		/*
1200 		 * If a packet is not multicast, we assume it is unicast.
1201 		 */
1202 		if (IN6_IS_ADDR_MULTICAST(&to)) {
1203 			is_unicast = ISC_FALSE;
1204 		} else {
1205 			is_unicast = ISC_TRUE;
1206 		}
1207 
1208 		ifrom.len = 16;
1209 		memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len);
1210 
1211 		/* Seek forward to find the matching source interface. */
1212 		ip = interfaces;
1213 		while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx))
1214 			ip = ip->next;
1215 
1216 		if (ip == NULL)
1217 			return ISC_R_NOTFOUND;
1218 
1219 		(*dhcpv6_packet_handler)(ip, buf,
1220 					 result, from.sin6_port,
1221 					 &ifrom, is_unicast);
1222 	}
1223 
1224 	return ISC_R_SUCCESS;
1225 }
1226 #endif /* DHCPv6 */
1227 
1228 isc_result_t dhcp_interface_set_value  (omapi_object_t *h,
1229 					omapi_object_t *id,
1230 					omapi_data_string_t *name,
1231 					omapi_typed_data_t *value)
1232 {
1233 	struct interface_info *interface;
1234 	isc_result_t status;
1235 
1236 	if (h -> type != dhcp_type_interface)
1237 		return DHCP_R_INVALIDARG;
1238 	interface = (struct interface_info *)h;
1239 
1240 	if (!omapi_ds_strcmp (name, "name")) {
1241 		if ((value -> type == omapi_datatype_data ||
1242 		     value -> type == omapi_datatype_string) &&
1243 		    value -> u.buffer.len < sizeof interface -> name) {
1244 			memcpy (interface -> name,
1245 				value -> u.buffer.value,
1246 				value -> u.buffer.len);
1247 			interface -> name [value -> u.buffer.len] = 0;
1248 		} else
1249 			return DHCP_R_INVALIDARG;
1250 		return ISC_R_SUCCESS;
1251 	}
1252 
1253 	/* Try to find some inner object that can take the value. */
1254 	if (h -> inner && h -> inner -> type -> set_value) {
1255 		status = ((*(h -> inner -> type -> set_value))
1256 			  (h -> inner, id, name, value));
1257 		if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
1258 			return status;
1259 	}
1260 
1261 	return ISC_R_NOTFOUND;
1262 }
1263 
1264 
1265 isc_result_t dhcp_interface_get_value (omapi_object_t *h,
1266 				       omapi_object_t *id,
1267 				       omapi_data_string_t *name,
1268 				       omapi_value_t **value)
1269 {
1270 	return ISC_R_NOTIMPLEMENTED;
1271 }
1272 
1273 isc_result_t dhcp_interface_destroy (omapi_object_t *h,
1274 					 const char *file, int line)
1275 {
1276 	struct interface_info *interface;
1277 
1278 	if (h -> type != dhcp_type_interface)
1279 		return DHCP_R_INVALIDARG;
1280 	interface = (struct interface_info *)h;
1281 
1282 	if (interface -> ifp) {
1283 		dfree (interface -> ifp, file, line);
1284 		interface -> ifp = 0;
1285 	}
1286 	if (interface -> next)
1287 		interface_dereference (&interface -> next, file, line);
1288 	if (interface -> rbuf) {
1289 		dfree (interface -> rbuf, file, line);
1290 		interface -> rbuf = (unsigned char *)0;
1291 	}
1292 	if (interface -> client)
1293 		interface -> client = (struct client_state *)0;
1294 
1295 	if (interface -> shared_network)
1296 		omapi_object_dereference ((void *)
1297 					  &interface -> shared_network, MDL);
1298 
1299 	return ISC_R_SUCCESS;
1300 }
1301 
1302 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
1303 					    const char *name, va_list ap)
1304 {
1305 	struct interface_info *ip, *interface;
1306 	isc_result_t status;
1307 
1308 	if (h -> type != dhcp_type_interface)
1309 		return DHCP_R_INVALIDARG;
1310 	interface = (struct interface_info *)h;
1311 
1312 	/* If it's an update signal, see if the interface is dead right
1313 	   now, or isn't known at all, and if that's the case, revive it. */
1314 	if (!strcmp (name, "update")) {
1315 		for (ip = dummy_interfaces; ip; ip = ip -> next)
1316 			if (ip == interface)
1317 				break;
1318 		if (ip && dhcp_interface_startup_hook)
1319 			return (*dhcp_interface_startup_hook) (ip);
1320 
1321 		for (ip = interfaces; ip; ip = ip -> next)
1322 			if (ip == interface)
1323 				break;
1324 		if (!ip && dhcp_interface_startup_hook)
1325 			return (*dhcp_interface_startup_hook) (ip);
1326 	}
1327 
1328 	/* Try to find some inner object that can take the value. */
1329 	if (h -> inner && h -> inner -> type -> signal_handler) {
1330 		status = ((*(h -> inner -> type -> signal_handler))
1331 			  (h -> inner, name, ap));
1332 		if (status == ISC_R_SUCCESS)
1333 			return status;
1334 	}
1335 	return ISC_R_NOTFOUND;
1336 }
1337 
1338 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
1339 					  omapi_object_t *id,
1340 					  omapi_object_t *h)
1341 {
1342 	struct interface_info *interface;
1343 	isc_result_t status;
1344 
1345 	if (h -> type != dhcp_type_interface)
1346 		return DHCP_R_INVALIDARG;
1347 	interface = (struct interface_info *)h;
1348 
1349 	/* Write out all the values. */
1350 
1351 	status = omapi_connection_put_name (c, "state");
1352 	if (status != ISC_R_SUCCESS)
1353 		return status;
1354 	if ((interface->flags & INTERFACE_REQUESTED) != 0)
1355 	    status = omapi_connection_put_string (c, "up");
1356 	else
1357 	    status = omapi_connection_put_string (c, "down");
1358 	if (status != ISC_R_SUCCESS)
1359 		return status;
1360 
1361 	/* Write out the inner object, if any. */
1362 	if (h -> inner && h -> inner -> type -> stuff_values) {
1363 		status = ((*(h -> inner -> type -> stuff_values))
1364 			  (c, id, h -> inner));
1365 		if (status == ISC_R_SUCCESS)
1366 			return status;
1367 	}
1368 
1369 	return ISC_R_SUCCESS;
1370 }
1371 
1372 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
1373 				    omapi_object_t *id,
1374 				    omapi_object_t *ref)
1375 {
1376 	omapi_value_t *tv = (omapi_value_t *)0;
1377 	isc_result_t status;
1378 	struct interface_info *interface;
1379 
1380 	if (!ref)
1381 		return DHCP_R_NOKEYS;
1382 
1383 	/* First see if we were sent a handle. */
1384 	status = omapi_get_value_str (ref, id, "handle", &tv);
1385 	if (status == ISC_R_SUCCESS) {
1386 		status = omapi_handle_td_lookup (ip, tv -> value);
1387 
1388 		omapi_value_dereference (&tv, MDL);
1389 		if (status != ISC_R_SUCCESS)
1390 			return status;
1391 
1392 		/* Don't return the object if the type is wrong. */
1393 		if ((*ip) -> type != dhcp_type_interface) {
1394 			omapi_object_dereference (ip, MDL);
1395 			return DHCP_R_INVALIDARG;
1396 		}
1397 	}
1398 
1399 	/* Now look for an interface name. */
1400 	status = omapi_get_value_str (ref, id, "name", &tv);
1401 	if (status == ISC_R_SUCCESS) {
1402 		char *s;
1403 		unsigned len;
1404 		for (interface = interfaces; interface;
1405 		     interface = interface -> next) {
1406 		    s = memchr (interface -> name, 0, IFNAMSIZ);
1407 		    if (s)
1408 			    len = s - &interface -> name [0];
1409 		    else
1410 			    len = IFNAMSIZ;
1411 		    if ((tv -> value -> u.buffer.len == len &&
1412 			 !memcmp (interface -> name,
1413 				  (char *)tv -> value -> u.buffer.value,
1414 				  len)))
1415 			    break;
1416 		}
1417 		if (!interface) {
1418 		    for (interface = dummy_interfaces;
1419 			 interface; interface = interface -> next) {
1420 			    s = memchr (interface -> name, 0, IFNAMSIZ);
1421 			    if (s)
1422 				    len = s - &interface -> name [0];
1423 			    else
1424 				    len = IFNAMSIZ;
1425 			    if ((tv -> value -> u.buffer.len == len &&
1426 				 !memcmp (interface -> name,
1427 					  (char *)
1428 					  tv -> value -> u.buffer.value,
1429 					  len)))
1430 				    break;
1431 		    }
1432 		}
1433 
1434 		omapi_value_dereference (&tv, MDL);
1435 		if (*ip && *ip != (omapi_object_t *)interface) {
1436 			omapi_object_dereference (ip, MDL);
1437 			return DHCP_R_KEYCONFLICT;
1438 		} else if (!interface) {
1439 			if (*ip)
1440 				omapi_object_dereference (ip, MDL);
1441 			return ISC_R_NOTFOUND;
1442 		} else if (!*ip)
1443 			omapi_object_reference (ip,
1444 						(omapi_object_t *)interface,
1445 						MDL);
1446 	}
1447 
1448 	/* If we get to here without finding an interface, no valid key was
1449 	   specified. */
1450 	if (!*ip)
1451 		return DHCP_R_NOKEYS;
1452 	return ISC_R_SUCCESS;
1453 }
1454 
1455 /* actually just go discover the interface */
1456 isc_result_t dhcp_interface_create (omapi_object_t **lp,
1457 				    omapi_object_t *id)
1458 {
1459  	struct interface_info *hp;
1460 	isc_result_t status;
1461 
1462 	hp = (struct interface_info *)0;
1463 	status = interface_allocate (&hp, MDL);
1464  	if (status != ISC_R_SUCCESS)
1465 		return status;
1466  	hp -> flags = INTERFACE_REQUESTED;
1467 	status = interface_reference ((struct interface_info **)lp, hp, MDL);
1468 	interface_dereference (&hp, MDL);
1469 	return status;
1470 }
1471 
1472 isc_result_t dhcp_interface_remove (omapi_object_t *lp,
1473 				    omapi_object_t *id)
1474 {
1475  	struct interface_info *interface, *ip, *last;
1476 
1477 	interface = (struct interface_info *)lp;
1478 
1479 	/* remove from interfaces */
1480 	last = 0;
1481 	for (ip = interfaces; ip; ip = ip -> next) {
1482 		if (ip == interface) {
1483 			if (last) {
1484 				interface_dereference (&last -> next, MDL);
1485 				if (ip -> next)
1486 					interface_reference (&last -> next,
1487 							     ip -> next, MDL);
1488 			} else {
1489 				interface_dereference (&interfaces, MDL);
1490 				if (ip -> next)
1491 					interface_reference (&interfaces,
1492 							     ip -> next, MDL);
1493 			}
1494 			if (ip -> next)
1495 				interface_dereference (&ip -> next, MDL);
1496 			break;
1497 		}
1498 		last = ip;
1499 	}
1500 	if (!ip)
1501 		return ISC_R_NOTFOUND;
1502 
1503 	/* add the interface to the dummy_interface list */
1504 	if (dummy_interfaces) {
1505 		interface_reference (&interface -> next,
1506 				     dummy_interfaces, MDL);
1507 		interface_dereference (&dummy_interfaces, MDL);
1508 	}
1509 	interface_reference (&dummy_interfaces, interface, MDL);
1510 
1511 	/* do a DHCPRELEASE */
1512 	if (dhcp_interface_shutdown_hook)
1513 		(*dhcp_interface_shutdown_hook) (interface);
1514 
1515 	/* remove the io object */
1516 	omapi_unregister_io_object ((omapi_object_t *)interface);
1517 
1518 	switch(local_family) {
1519 #ifdef DHCPv6
1520 	case AF_INET6:
1521 		if_deregister6(interface);
1522 		break;
1523 #endif /* DHCPv6 */
1524 	case AF_INET:
1525 	default:
1526 		if_deregister_send(interface);
1527 		if_deregister_receive(interface);
1528 		break;
1529 	}
1530 
1531 	return ISC_R_SUCCESS;
1532 }
1533 
1534 void interface_stash (struct interface_info *tptr)
1535 {
1536 	struct interface_info **vec;
1537 	int delta;
1538 
1539 	/* If the registerer didn't assign an index, assign one now. */
1540 	if (tptr -> index == -1) {
1541 		tptr -> index = interface_count++;
1542 		while (tptr -> index < interface_max &&
1543 		       interface_vector [tptr -> index])
1544 			tptr -> index = interface_count++;
1545 	}
1546 
1547 	if (interface_max <= tptr -> index) {
1548 		delta = tptr -> index - interface_max + 10;
1549 		vec = dmalloc ((interface_max + delta) *
1550 			       sizeof (struct interface_info *), MDL);
1551 		if (!vec) {
1552 			log_error ("interface_stash: allocation failed ");
1553 			return;
1554 		}
1555 
1556 		memset (&vec [interface_max], 0,
1557 			(sizeof (struct interface_info *)) * delta);
1558 		interface_max += delta;
1559 		if (interface_vector) {
1560 		    memcpy (vec, interface_vector,
1561 			    (interface_count *
1562 			     sizeof (struct interface_info *)));
1563 		    dfree (interface_vector, MDL);
1564 		}
1565 
1566 		interface_vector = vec;
1567 	}
1568 
1569 	interface_reference (&interface_vector [tptr -> index], tptr, MDL);
1570 	if (tptr -> index >= interface_count)
1571 		interface_count = tptr -> index + 1;
1572 #if defined (TRACING)
1573 	trace_interface_register (interface_trace, tptr);
1574 #endif
1575 }
1576 
1577 void interface_snorf (struct interface_info *tmp, int ir)
1578 {
1579 	tmp -> circuit_id = (u_int8_t *)tmp -> name;
1580 	tmp -> circuit_id_len = strlen (tmp -> name);
1581 	tmp -> remote_id = 0;
1582 	tmp -> remote_id_len = 0;
1583 	tmp -> flags = ir;
1584 	if (interfaces) {
1585 		interface_reference (&tmp -> next,
1586 				     interfaces, MDL);
1587 		interface_dereference (&interfaces, MDL);
1588 	}
1589 	interface_reference (&interfaces, tmp, MDL);
1590 }
1591