Home | History | Annotate | Line # | Download | only in common
      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 (at) 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 
     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)
    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 
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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