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