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