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