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