3 Network input dispatcher... */
6 * Copyright (c) 2004-2005 by Internet Systems Consortium, Inc. ("ISC")
7 * Copyright (c) 1995-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
27 * This software has been written for Internet Systems Consortium
28 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29 * To learn more about Internet Systems Consortium, see
30 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
31 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32 * ``http://www.nominum.com''.
36 static char copyright
[] =
37 "$Id: discover.c,v 1.11 2007/10/31 15:26:51 gdt Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
41 #include <sys/ioctl.h>
44 struct interface_info
*interfaces
, *dummy_interfaces
, *fallback_interface
;
45 int interfaces_invalidated
;
46 int quiet_interface_discovery
;
48 u_int16_t remote_port
;
49 int (*dhcp_interface_setup_hook
) (struct interface_info
*, struct iaddr
*);
50 int (*dhcp_interface_discovery_hook
) (struct interface_info
*);
51 isc_result_t (*dhcp_interface_startup_hook
) (struct interface_info
*);
52 int (*dhcp_interface_shutdown_hook
) (struct interface_info
*);
54 struct in_addr limited_broadcast
;
55 struct in_addr local_address
;
57 void (*bootp_packet_handler
) PROTO ((struct interface_info
*,
58 struct dhcp_packet
*, unsigned,
60 struct iaddr
, struct hardware
*));
62 omapi_object_type_t
*dhcp_type_interface
;
64 trace_type_t
*interface_trace
;
65 trace_type_t
*inpacket_trace
;
66 trace_type_t
*outpacket_trace
;
68 struct interface_info
**interface_vector
;
72 OMAPI_OBJECT_ALLOC (interface
, struct interface_info
, dhcp_type_interface
)
74 isc_result_t
interface_setup ()
77 status
= omapi_object_type_register (&dhcp_type_interface
,
89 dhcp_interface_set_value
,
90 dhcp_interface_get_value
,
91 dhcp_interface_destroy
,
92 dhcp_interface_signal_handler
,
93 dhcp_interface_stuff_values
,
94 dhcp_interface_lookup
,
95 dhcp_interface_create
,
96 dhcp_interface_remove
,
99 sizeof (struct interface_info
),
100 interface_initialize
, RC_MISC
);
101 if (status
!= ISC_R_SUCCESS
)
102 log_fatal ("Can't register interface object type: %s",
103 isc_result_totext (status
));
108 #if defined (TRACING)
109 void interface_trace_setup ()
111 interface_trace
= trace_type_register ("interface", (void *)0,
112 trace_interface_input
,
113 trace_interface_stop
, MDL
);
114 inpacket_trace
= trace_type_register ("inpacket", (void *)0,
115 trace_inpacket_input
,
116 trace_inpacket_stop
, MDL
);
117 outpacket_trace
= trace_type_register ("outpacket", (void *)0,
118 trace_outpacket_input
,
119 trace_outpacket_stop
, MDL
);
123 isc_result_t
interface_initialize (omapi_object_t
*ipo
,
124 const char *file
, int line
)
126 struct interface_info
*ip
= (struct interface_info
*)ipo
;
127 ip
-> rfdesc
= ip
-> wfdesc
= -1;
128 return ISC_R_SUCCESS
;
131 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
132 For each interface that's of type INET and not the loopback interface,
133 register that interface with the network I/O software, figure out what
134 subnet it's on, and add it to the list of interfaces. */
136 void discover_interfaces (state
)
139 struct interface_info
*tmp
;
140 struct interface_info
*last
, *next
;
142 * Because the code to retry on SIOCGIFCONF not returning all
143 * interfaces is broken, use an unreasonably large buffer to
144 * handle the case of a machine with lots of (usually virtual)
152 struct subnet
*subnet
;
153 struct sockaddr_in foo
;
156 #ifdef ALIAS_NAMES_PERMUTED
160 static int setup_fallback
= 0;
163 /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
164 if ((sock
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) < 0)
165 log_fatal ("Can't create addrlist socket");
167 /* Get the interface configuration information... */
169 #ifdef SIOCGIFCONF_ZERO_PROBE
170 /* linux will only tell us how long a buffer it wants if we give it
171 * a null buffer first. So, do a dry run to figure out the length.
173 * XXX this code is duplicated from below because trying to fold
174 * the logic into the if statement and goto resulted in excesssive
175 * obfuscation. The intent is that unless you run Linux you shouldn't
176 * have to deal with this. */
179 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)NULL
;
181 /* otherwise, we just feed it a starting size, and it'll tell us if
184 ic
.ifc_len
= sizeof buf
;
185 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)buf
;
189 i
= ioctl(sock
, SIOCGIFCONF
, &ic
);
192 log_fatal ("ioctl: SIOCGIFCONF: %m");
194 #ifdef SIOCGIFCONF_ZERO_PROBE
195 /* Workaround for SIOCGIFCONF bug on some Linux versions. */
196 if (ic
.ifc_ifcu
.ifcu_buf
== 0 && ic
.ifc_len
== 0) {
197 ic
.ifc_len
= sizeof buf
;
198 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)buf
;
203 /* If the SIOCGIFCONF resulted in more data than would fit in
204 a buffer, allocate a bigger buffer. */
206 * XXX This code is broken on NetBSD; the return value is the
207 * amount of data returned, not the amount that would be
208 * needed. We need to e.g. double the buffer and try again.
209 * The proper test is hairier: we can be sure that we got
210 * everything only if there is an entire struct ifreq worth of
213 if ((ic
.ifc_ifcu
.ifcu_buf
== buf
214 #ifdef SIOCGIFCONF_ZERO_PROBE
215 || ic
.ifc_ifcu
.ifcu_buf
== 0
217 ) && ic
.ifc_len
> sizeof buf
) {
218 ic
.ifc_ifcu
.ifcu_buf
= dmalloc ((size_t)ic
.ifc_len
, MDL
);
219 if (!ic
.ifc_ifcu
.ifcu_buf
)
220 log_fatal ("Can't allocate SIOCGIFCONF buffer.");
222 #ifdef SIOCGIFCONF_ZERO_PROBE
223 } else if (ic
.ifc_ifcu
.ifcu_buf
== 0) {
224 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)buf
;
225 ic
.ifc_len
= sizeof buf
;
231 /* If we already have a list of interfaces, and we're running as
232 a DHCP server, the interfaces were requested. */
233 if (interfaces
&& (state
== DISCOVER_SERVER
||
234 state
== DISCOVER_RELAY
||
235 state
== DISCOVER_REQUESTED
))
237 else if (state
== DISCOVER_UNCONFIGURED
)
238 ir
= INTERFACE_REQUESTED
| INTERFACE_AUTOMATIC
;
240 ir
= INTERFACE_REQUESTED
;
242 /* Cycle through the list of interfaces looking for IP addresses. */
243 for (i
= 0; i
< ic
.ifc_len
;) {
248 struct ifreq
*ifp
= &ifcpy
.ifr
;
250 memcpy(&ifcpy
, (caddr_t
)ic
.ifc_req
+ i
, sizeof(struct ifreq
));
253 * Classically, struct ifreq used with SIOCGIFCONF had
254 * a union where struct sockaddr was the largest
255 * member. If the address fit in the union, the next
256 * ifreq followed immediately. If not, the next ifreq
257 * followed the end of the actual sockaddr. In
258 * NetBSD-current after ~2007-05, ifreq has a
259 * sockaddr_storage member, and the next ifreq follows
260 * the current ifreq always, because no sockaddr can
261 * be bigger than sockaddr_storage. Thus, compare the
262 * length to the union's size, not struct sockaddr.
264 if (ifp
-> ifr_addr
.sa_len
> sizeof (ifp
->ifr_ifru
)) {
265 if (sizeof(struct ifreq
) + ifp
->ifr_addr
.sa_len
>
268 /* XXX This copies IFNAMSIZ bytes too many. */
269 memcpy(&ifcpy
, (caddr_t
)ic
.ifc_req
+ i
,
270 sizeof(struct ifreq
) + ifp
->ifr_addr
.sa_len
);
271 i
+= offsetof(struct ifreq
, ifr_ifru
) +
272 ifp
-> ifr_addr
.sa_len
;
277 #ifdef ALIAS_NAMES_PERMUTED
278 if ((s
= strrchr (ifp
-> ifr_name
, ':'))) {
283 #ifdef SKIP_DUMMY_INTERFACES
284 if (!strncmp (ifp
-> ifr_name
, "dummy", 5))
289 /* See if this is the sort of interface we want to
291 strcpy (ifr
.ifr_name
, ifp
-> ifr_name
);
292 if (ioctl (sock
, SIOCGIFFLAGS
, &ifr
) < 0)
293 log_fatal ("Can't get interface flags for %s: %m",
296 /* See if we've seen an interface that matches this one. */
297 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
)
298 if (!strcmp (tmp
-> name
, ifp
-> ifr_name
))
301 /* Skip non broadcast interfaces (plus loopback and
302 point-to-point in case an OS incorrectly marks them
303 as broadcast). Also skip down interfaces unless we're
304 trying to get a list of configurable interfaces. */
305 if (((!(ifr
.ifr_flags
& IFF_BROADCAST
) ||
306 ifr
.ifr_flags
& IFF_LOOPBACK
||
307 ifr
.ifr_flags
& IFF_POINTOPOINT
) && !tmp
) ||
308 (!(ifr
.ifr_flags
& IFF_UP
) &&
309 state
!= DISCOVER_UNCONFIGURED
))
312 /* If there isn't already an interface by this name,
315 tmp
= (struct interface_info
*)0;
316 status
= interface_allocate (&tmp
, MDL
);
317 if (status
!= ISC_R_SUCCESS
)
318 log_fatal ("Error allocating interface %s: %s",
320 isc_result_totext (status
));
321 strcpy (tmp
-> name
, ifp
-> ifr_name
);
322 interface_snorf (tmp
, ir
);
323 interface_dereference (&tmp
, MDL
);
324 tmp
= interfaces
; /* XXX */
327 if (dhcp_interface_discovery_hook
)
328 (*dhcp_interface_discovery_hook
) (tmp
);
330 /* If we have the capability, extract link information
331 and record it in a linked list. */
333 if (ifp
-> ifr_addr
.sa_family
== AF_LINK
) {
334 struct sockaddr_dl
*foo
= ((struct sockaddr_dl
*)
336 #if defined (HAVE_SIN_LEN)
337 tmp
-> hw_address
.hlen
= foo
-> sdl_alen
;
339 tmp
-> hw_address
.hlen
= 6; /* XXX!!! */
341 if (foo
-> sdl_type
== IFT_ETHER
) {
342 tmp
-> hw_address
.hbuf
[0] = HTYPE_ETHER
;
343 #if defined (DEC_FDDI) || defined(NETBSD_FDDI)
344 } else if (foo
-> sdl_type
== IFT_FDDI
) {
345 tmp
-> hw_address
.hbuf
[0] = HTYPE_FDDI
;
350 memcpy (&tmp
-> hw_address
.hbuf
[1],
351 LLADDR (foo
), tmp
-> hw_address
.hlen
);
352 tmp
-> hw_address
.hlen
++; /* for type. */
356 if (ifp
-> ifr_addr
.sa_family
== AF_INET
) {
360 /* Get a pointer to the address... */
361 ptr
= &ifp
-> ifr_addr
;
362 memcpy (&foo
, ptr
, sizeof ifp
-> ifr_addr
);
364 /* We don't want the loopback interface. */
365 if (foo
.sin_addr
.s_addr
== htonl (INADDR_LOOPBACK
) &&
366 ((tmp
-> flags
& INTERFACE_AUTOMATIC
) &&
367 state
== DISCOVER_SERVER
))
371 /* If this is the first real IP address we've
372 found, keep a pointer to ifreq structure in
373 which we found it. */
376 unsigned len
= offsetof(struct ifreq
, ifr_ifru
)
377 + ifp
-> ifr_addr
.sa_len
;
379 unsigned len
= sizeof *ifp
;
381 tif
= (struct ifreq
*)dmalloc (len
, MDL
);
383 log_fatal ("no space for ifp.");
384 memcpy (tif
, ifp
, len
);
386 tmp
-> primary_address
= foo
.sin_addr
;
389 /* Grab the address... */
391 memcpy (addr
.iabuf
, &foo
.sin_addr
.s_addr
,
393 if (dhcp_interface_setup_hook
)
394 (*dhcp_interface_setup_hook
) (tmp
, &addr
);
398 /* If we allocated a buffer, free it. */
399 if (ic
.ifc_ifcu
.ifcu_buf
!= buf
)
400 dfree (ic
.ifc_ifcu
.ifcu_buf
, MDL
);
402 #if defined (LINUX_SLASHPROC_DISCOVERY)
403 /* On Linux, interfaces that don't have IP addresses don't
404 show up in the SIOCGIFCONF syscall. This only matters for
405 the DHCP client, of course - the relay agent and server
406 should only care about interfaces that are configured with
409 The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
410 that, when read, prints a human readable network status. We
411 extract the names of the network devices by skipping the first
412 two lines (which are header) and then parsing off everything
413 up to the colon in each subsequent line - these lines start
414 with the interface name, then a colon, then a bunch of
417 if (state
== DISCOVER_UNCONFIGURED
) {
422 proc_dev
= fopen (PROCDEV_DEVICE
, "r");
424 log_fatal ("%s: %m", PROCDEV_DEVICE
);
426 while (fgets (buffer
, sizeof buffer
, proc_dev
)) {
430 /* Skip the first two blocks, which are header
437 sep
= strrchr (buffer
, ':');
443 /* See if we've seen an interface that matches
445 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
)
446 if (!strcmp (tmp
-> name
, name
))
449 /* If we found one, nothing more to do.. */
453 strncpy (ifr
.ifr_name
, name
, IFNAMSIZ
);
455 /* Skip non broadcast interfaces (plus loopback and
456 * point-to-point in case an OS incorrectly marks them
459 if ((ioctl (sock
, SIOCGIFFLAGS
, &ifr
) < 0) ||
460 (!(ifr
.ifr_flags
& IFF_BROADCAST
)) ||
461 (ifr
.ifr_flags
& IFF_LOOPBACK
) ||
462 (ifr
.ifr_flags
& IFF_POINTOPOINT
))
465 /* Otherwise, allocate one. */
466 tmp
= (struct interface_info
*)0;
467 status
= interface_allocate (&tmp
, MDL
);
468 if (status
!= ISC_R_SUCCESS
)
469 log_fatal ("Can't allocate interface %s: %s",
470 name
, isc_result_totext (status
));
472 strncpy (tmp
-> name
, name
, IFNAMSIZ
);
474 interface_reference (&tmp
-> next
,
476 interface_dereference (&interfaces
, MDL
);
478 interface_reference (&interfaces
, tmp
, MDL
);
479 interface_dereference (&tmp
, MDL
);
482 if (dhcp_interface_discovery_hook
)
483 (*dhcp_interface_discovery_hook
) (tmp
);
490 /* Now cycle through all the interfaces we found, looking for
491 hardware addresses. */
492 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
493 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
) {
499 /* Make up an ifreq structure. */
500 tif
= (struct ifreq
*)dmalloc (sizeof (struct ifreq
),
503 log_fatal ("no space to remember ifp.");
504 memset (tif
, 0, sizeof (struct ifreq
));
505 strcpy (tif
-> ifr_name
, tmp
-> name
);
509 /* Read the hardware address from this interface. */
511 if (ioctl (sock
, SIOCGIFHWADDR
, &ifr
) < 0)
514 sa
= *(struct sockaddr
*)&ifr
.ifr_hwaddr
;
516 switch (sa
.sa_family
) {
517 #ifdef HAVE_ARPHRD_TUNNEL
519 /* ignore tunnel interfaces. */
521 #ifdef HAVE_ARPHRD_ROSE
524 #ifdef HAVE_ARPHRD_LOOPBACK
525 case ARPHRD_LOOPBACK
:
526 /* ignore loopback interface */
531 tmp
-> hw_address
.hlen
= 7;
532 tmp
-> hw_address
.hbuf
[0] = ARPHRD_ETHER
;
533 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
536 #ifndef HAVE_ARPHRD_IEEE802
537 # define ARPHRD_IEEE802 HTYPE_IEEE802
539 #if defined (HAVE_ARPHRD_IEEE802_TR)
540 case ARPHRD_IEEE802_TR
:
543 tmp
-> hw_address
.hlen
= 7;
544 tmp
-> hw_address
.hbuf
[0] = ARPHRD_IEEE802
;
545 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
548 #ifndef HAVE_ARPHRD_FDDI
549 # define ARPHRD_FDDI HTYPE_FDDI
552 tmp
-> hw_address
.hlen
= 17;
553 tmp
-> hw_address
.hbuf
[0] = HTYPE_FDDI
; /* XXX */
554 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 16);
557 #ifdef HAVE_ARPHRD_METRICOM
558 case ARPHRD_METRICOM
:
559 tmp
-> hw_address
.hlen
= 7;
560 tmp
-> hw_address
.hbuf
[0] = ARPHRD_METRICOM
;
561 memcpy (&tmp
-> hw_address
.hbuf
[0], sa
.sa_data
, 6);
565 #ifdef HAVE_ARPHRD_AX25
567 tmp
-> hw_address
.hlen
= 7;
568 tmp
-> hw_address
.hbuf
[0] = ARPHRD_AX25
;
569 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
573 #ifdef HAVE_ARPHRD_NETROM
575 tmp
-> hw_address
.hlen
= 7;
576 tmp
-> hw_address
.hbuf
[0] = ARPHRD_NETROM
;
577 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
582 log_error ("%s: unknown hardware address type %d",
583 ifr
.ifr_name
, sa
.sa_family
);
587 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
589 /* If we're just trying to get a list of interfaces that we might
590 be able to configure, we can quit now. */
591 if (state
== DISCOVER_UNCONFIGURED
) {
596 /* Weed out the interfaces that did not have IP addresses. */
597 tmp
= last
= next
= (struct interface_info
*)0;
599 interface_reference (&tmp
, interfaces
, MDL
);
602 interface_dereference (&next
, MDL
);
604 interface_reference (&next
, tmp
-> next
, MDL
);
605 /* skip interfaces that are running already */
606 if (tmp
-> flags
& INTERFACE_RUNNING
) {
607 interface_dereference(&tmp
, MDL
);
609 interface_reference(&tmp
, next
, MDL
);
612 if ((tmp
-> flags
& INTERFACE_AUTOMATIC
) &&
613 state
== DISCOVER_REQUESTED
)
614 tmp
-> flags
&= ~(INTERFACE_AUTOMATIC
|
615 INTERFACE_REQUESTED
);
616 if (!tmp
-> ifp
|| !(tmp
-> flags
& INTERFACE_REQUESTED
)) {
617 if ((tmp
-> flags
& INTERFACE_REQUESTED
) != ir
)
618 log_fatal ("%s: not found", tmp
-> name
);
621 interface_dereference (&interfaces
,
624 interface_reference (&interfaces
, next
, MDL
);
626 interface_dereference (&last
-> next
, MDL
);
628 interface_reference (&last
-> next
,
632 interface_dereference (&tmp
-> next
, MDL
);
634 /* Remember the interface in case we need to know
636 if (dummy_interfaces
) {
637 interface_reference (&tmp
-> next
,
638 dummy_interfaces
, MDL
);
639 interface_dereference (&dummy_interfaces
, MDL
);
641 interface_reference (&dummy_interfaces
, tmp
, MDL
);
642 interface_dereference (&tmp
, MDL
);
644 interface_reference (&tmp
, next
, MDL
);
649 memcpy (&foo
, &tmp
-> ifp
-> ifr_addr
,
650 sizeof tmp
-> ifp
-> ifr_addr
);
652 /* We must have a subnet declaration for each interface. */
653 if (!tmp
-> shared_network
&& (state
== DISCOVER_SERVER
)) {
654 log_error ("%s", "");
655 log_error ("No subnet declaration for %s (%s).",
656 tmp
-> name
, inet_ntoa (foo
.sin_addr
));
657 if (supports_multiple_interfaces (tmp
)) {
658 log_error ("** Ignoring requests on %s. %s",
659 tmp
-> name
, "If this is not what");
660 log_error (" you want, please write %s",
661 "a subnet declaration");
662 log_error (" in your dhcpd.conf file %s",
663 "for the network segment");
664 log_error (" to %s %s %s",
666 tmp
-> name
, "is attached. **");
667 log_error ("%s", "");
670 log_error ("You must write a subnet %s",
671 " declaration for this");
672 log_error ("subnet. You cannot prevent %s",
674 log_error ("from listening on this subnet %s",
676 log_fatal ("operating system does not %s.",
677 "support this capability");
681 /* Find subnets that don't have valid interface
683 for (subnet
= (tmp
-> shared_network
684 ? tmp
-> shared_network
-> subnets
685 : (struct subnet
*)0);
686 subnet
; subnet
= subnet
-> next_sibling
) {
687 if (!subnet
-> interface_address
.len
) {
688 /* Set the interface address for this subnet
689 to the first address we found. */
690 subnet
-> interface_address
.len
= 4;
691 memcpy (subnet
-> interface_address
.iabuf
,
692 &foo
.sin_addr
.s_addr
, 4);
696 /* Flag the index as not having been set, so that the
697 interface registerer can set it or not as it chooses. */
700 /* Register the interface... */
701 if_register_receive (tmp
);
702 if_register_send (tmp
);
704 interface_stash (tmp
);
706 #if defined (HAVE_SETFD)
707 if (fcntl (tmp
-> rfdesc
, F_SETFD
, 1) < 0)
708 log_error ("Can't set close-on-exec on %s: %m",
710 if (tmp
-> rfdesc
!= tmp
-> wfdesc
) {
711 if (fcntl (tmp
-> wfdesc
, F_SETFD
, 1) < 0)
712 log_error ("Can't set close-on-exec on %s: %m",
717 interface_dereference (&tmp
, MDL
);
719 interface_reference (&tmp
, next
, MDL
);
722 /* Now register all the remaining interfaces as protocols. */
723 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
) {
724 /* not if it's been registered before */
725 if (tmp
-> flags
& INTERFACE_RUNNING
)
727 if (tmp
-> rfdesc
== -1)
729 status
= omapi_register_io_object ((omapi_object_t
*)tmp
,
732 if (status
!= ISC_R_SUCCESS
)
733 log_fatal ("Can't register I/O handle for %s: %s",
734 tmp
-> name
, isc_result_totext (status
));
739 if (state
== DISCOVER_SERVER
&& wifcount
== 0) {
741 log_fatal ("Not configured to listen on any interfaces!");
744 if (!setup_fallback
) {
746 maybe_setup_fallback ();
749 #if defined (HAVE_SETFD)
750 if (fallback_interface
) {
751 if (fcntl (fallback_interface
-> rfdesc
, F_SETFD
, 1) < 0)
752 log_error ("Can't set close-on-exec on fallback: %m");
753 if (fallback_interface
-> rfdesc
!= fallback_interface
-> wfdesc
) {
754 if (fcntl (fallback_interface
-> wfdesc
, F_SETFD
, 1) < 0)
755 log_error ("Can't set close-on-exec on fallback: %m");
761 int if_readsocket (h
)
764 struct interface_info
*ip
;
766 if (h
-> type
!= dhcp_type_interface
)
768 ip
= (struct interface_info
*)h
;
772 int setup_fallback (struct interface_info
**fp
, const char *file
, int line
)
776 status
= interface_allocate (&fallback_interface
, file
, line
);
777 if (status
!= ISC_R_SUCCESS
)
778 log_fatal ("Error allocating fallback interface: %s",
779 isc_result_totext (status
));
780 strcpy (fallback_interface
-> name
, "fallback");
781 if (dhcp_interface_setup_hook
)
782 (*dhcp_interface_setup_hook
) (fallback_interface
,
784 status
= interface_reference (fp
, fallback_interface
, file
, line
);
786 fallback_interface
-> index
= -1;
787 interface_stash (fallback_interface
);
788 return status
== ISC_R_SUCCESS
;
791 void reinitialize_interfaces ()
793 struct interface_info
*ip
;
795 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
796 if_reinitialize_receive (ip
);
797 if_reinitialize_send (ip
);
800 if (fallback_interface
)
801 if_reinitialize_send (fallback_interface
);
803 interfaces_invalidated
= 1;
806 isc_result_t
got_one (h
)
809 struct sockaddr_in from
;
810 struct hardware hfrom
;
814 unsigned char packbuf
[4095]; /* Packet input buffer.
815 Must be as large as largest
817 struct dhcp_packet packet
;
819 struct interface_info
*ip
;
821 if (h
-> type
!= dhcp_type_interface
)
822 return ISC_R_INVALIDARG
;
823 ip
= (struct interface_info
*)h
;
827 receive_packet (ip
, u
.packbuf
, sizeof u
, &from
, &hfrom
)) < 0) {
828 log_error ("receive_packet failed on %s: %m", ip
-> name
);
829 return ISC_R_UNEXPECTED
;
832 return ISC_R_UNEXPECTED
;
834 if (bootp_packet_handler
) {
836 memcpy (ifrom
.iabuf
, &from
.sin_addr
, ifrom
.len
);
838 (*bootp_packet_handler
) (ip
, &u
.packet
, (unsigned)result
,
839 from
.sin_port
, ifrom
, &hfrom
);
842 /* If there is buffered data, read again. This is for, e.g.,
843 bpf, which may return two packets at once. */
844 if (ip
-> rbuf_offset
!= ip
-> rbuf_len
)
846 return ISC_R_SUCCESS
;
850 isc_result_t
dhcp_interface_set_value (omapi_object_t
*h
,
852 omapi_data_string_t
*name
,
853 omapi_typed_data_t
*value
)
855 struct interface_info
*interface
;
858 if (h
-> type
!= dhcp_type_interface
)
859 return ISC_R_INVALIDARG
;
860 interface
= (struct interface_info
*)h
;
862 if (!omapi_ds_strcmp (name
, "name")) {
863 if ((value
-> type
== omapi_datatype_data
||
864 value
-> type
== omapi_datatype_string
) &&
865 value
-> u
.buffer
.len
< sizeof interface
-> name
) {
866 memcpy (interface
-> name
,
867 value
-> u
.buffer
.value
,
868 value
-> u
.buffer
.len
);
869 interface
-> name
[value
-> u
.buffer
.len
] = 0;
871 return ISC_R_INVALIDARG
;
872 return ISC_R_SUCCESS
;
875 /* Try to find some inner object that can take the value. */
876 if (h
-> inner
&& h
-> inner
-> type
-> set_value
) {
877 status
= ((*(h
-> inner
-> type
-> set_value
))
878 (h
-> inner
, id
, name
, value
));
879 if (status
== ISC_R_SUCCESS
|| status
== ISC_R_UNCHANGED
)
883 return ISC_R_NOTFOUND
;
887 isc_result_t
dhcp_interface_get_value (omapi_object_t
*h
,
889 omapi_data_string_t
*name
,
890 omapi_value_t
**value
)
892 return ISC_R_NOTIMPLEMENTED
;
895 isc_result_t
dhcp_interface_destroy (omapi_object_t
*h
,
896 const char *file
, int line
)
898 struct interface_info
*interface
;
900 if (h
-> type
!= dhcp_type_interface
)
901 return ISC_R_INVALIDARG
;
902 interface
= (struct interface_info
*)h
;
904 if (interface
-> ifp
) {
905 dfree (interface
-> ifp
, file
, line
);
906 interface
-> ifp
= 0;
908 if (interface
-> next
)
909 interface_dereference (&interface
-> next
, file
, line
);
910 if (interface
-> rbuf
) {
911 dfree (interface
-> rbuf
, file
, line
);
912 interface
-> rbuf
= (unsigned char *)0;
914 if (interface
-> client
)
915 interface
-> client
= (struct client_state
*)0;
917 if (interface
-> shared_network
)
918 omapi_object_dereference ((omapi_object_t
**)
919 &interface
-> shared_network
, MDL
);
921 return ISC_R_SUCCESS
;
924 isc_result_t
dhcp_interface_signal_handler (omapi_object_t
*h
,
925 const char *name
, va_list ap
)
927 struct interface_info
*ip
, *interface
;
930 if (h
-> type
!= dhcp_type_interface
)
931 return ISC_R_INVALIDARG
;
932 interface
= (struct interface_info
*)h
;
934 /* If it's an update signal, see if the interface is dead right
935 now, or isn't known at all, and if that's the case, revive it. */
936 if (!strcmp (name
, "update")) {
937 for (ip
= dummy_interfaces
; ip
; ip
= ip
-> next
)
940 if (ip
&& dhcp_interface_startup_hook
)
941 return (*dhcp_interface_startup_hook
) (ip
);
943 for (ip
= interfaces
; ip
; ip
= ip
-> next
)
946 if (!ip
&& dhcp_interface_startup_hook
)
947 return (*dhcp_interface_startup_hook
) (ip
);
950 /* Try to find some inner object that can take the value. */
951 if (h
-> inner
&& h
-> inner
-> type
-> get_value
) {
952 status
= ((*(h
-> inner
-> type
-> signal_handler
))
953 (h
-> inner
, name
, ap
));
954 if (status
== ISC_R_SUCCESS
)
957 return ISC_R_NOTFOUND
;
960 isc_result_t
dhcp_interface_stuff_values (omapi_object_t
*c
,
964 struct interface_info
*interface
;
967 if (h
-> type
!= dhcp_type_interface
)
968 return ISC_R_INVALIDARG
;
969 interface
= (struct interface_info
*)h
;
971 /* Write out all the values. */
973 status
= omapi_connection_put_name (c
, "state");
974 if (status
!= ISC_R_SUCCESS
)
976 if (interface
-> flags
&& INTERFACE_REQUESTED
)
977 status
= omapi_connection_put_string (c
, "up");
979 status
= omapi_connection_put_string (c
, "down");
980 if (status
!= ISC_R_SUCCESS
)
983 /* Write out the inner object, if any. */
984 if (h
-> inner
&& h
-> inner
-> type
-> stuff_values
) {
985 status
= ((*(h
-> inner
-> type
-> stuff_values
))
986 (c
, id
, h
-> inner
));
987 if (status
== ISC_R_SUCCESS
)
991 return ISC_R_SUCCESS
;
994 isc_result_t
dhcp_interface_lookup (omapi_object_t
**ip
,
998 omapi_value_t
*tv
= (omapi_value_t
*)0;
1000 struct interface_info
*interface
;
1003 return ISC_R_NOKEYS
;
1005 /* First see if we were sent a handle. */
1006 status
= omapi_get_value_str (ref
, id
, "handle", &tv
);
1007 if (status
== ISC_R_SUCCESS
) {
1008 status
= omapi_handle_td_lookup (ip
, tv
-> value
);
1010 omapi_value_dereference (&tv
, MDL
);
1011 if (status
!= ISC_R_SUCCESS
)
1014 /* Don't return the object if the type is wrong. */
1015 if ((*ip
) -> type
!= dhcp_type_interface
) {
1016 omapi_object_dereference (ip
, MDL
);
1017 return ISC_R_INVALIDARG
;
1021 /* Now look for an interface name. */
1022 status
= omapi_get_value_str (ref
, id
, "name", &tv
);
1023 if (status
== ISC_R_SUCCESS
) {
1026 for (interface
= interfaces
; interface
;
1027 interface
= interface
-> next
) {
1028 s
= memchr (interface
-> name
, 0, IFNAMSIZ
);
1030 len
= s
- &interface
-> name
[0];
1033 if ((tv
-> value
-> u
.buffer
.len
== len
&&
1034 !memcmp (interface
-> name
,
1035 (char *)tv
-> value
-> u
.buffer
.value
,
1040 for (interface
= dummy_interfaces
;
1041 interface
; interface
= interface
-> next
) {
1042 s
= memchr (interface
-> name
, 0, IFNAMSIZ
);
1044 len
= s
- &interface
-> name
[0];
1047 if ((tv
-> value
-> u
.buffer
.len
== len
&&
1048 !memcmp (interface
-> name
,
1050 tv
-> value
-> u
.buffer
.value
,
1056 omapi_value_dereference (&tv
, MDL
);
1057 if (*ip
&& *ip
!= (omapi_object_t
*)interface
) {
1058 omapi_object_dereference (ip
, MDL
);
1059 return ISC_R_KEYCONFLICT
;
1060 } else if (!interface
) {
1062 omapi_object_dereference (ip
, MDL
);
1063 return ISC_R_NOTFOUND
;
1065 omapi_object_reference (ip
,
1066 (omapi_object_t
*)interface
,
1070 /* If we get to here without finding an interface, no valid key was
1073 return ISC_R_NOKEYS
;
1074 return ISC_R_SUCCESS
;
1077 /* actually just go discover the interface */
1078 isc_result_t
dhcp_interface_create (omapi_object_t
**lp
,
1081 struct interface_info
*hp
;
1082 isc_result_t status
;
1084 hp
= (struct interface_info
*)0;
1085 status
= interface_allocate (&hp
, MDL
);
1086 if (status
!= ISC_R_SUCCESS
)
1088 hp
-> flags
= INTERFACE_REQUESTED
;
1089 status
= interface_reference ((struct interface_info
**)lp
, hp
, MDL
);
1090 interface_dereference (&hp
, MDL
);
1095 isc_result_t
dhcp_interface_remove (omapi_object_t
*lp
,
1098 struct interface_info
*interface
, *ip
, *last
;
1100 interface
= (struct interface_info
*)lp
;
1102 /* remove from interfaces */
1104 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
1105 if (ip
== interface
) {
1107 interface_dereference (&last
-> next
, MDL
);
1109 interface_reference (&last
-> next
,
1112 interface_dereference (&interfaces
, MDL
);
1114 interface_reference (&interfaces
,
1118 interface_dereference (&ip
-> next
, MDL
);
1124 return ISC_R_NOTFOUND
;
1126 /* add the interface to the dummy_interface list */
1127 if (dummy_interfaces
) {
1128 interface_reference (&interface
-> next
,
1129 dummy_interfaces
, MDL
);
1130 interface_dereference (&dummy_interfaces
, MDL
);
1132 interface_reference (&dummy_interfaces
, interface
, MDL
);
1134 /* do a DHCPRELEASE */
1135 if (dhcp_interface_shutdown_hook
)
1136 (*dhcp_interface_shutdown_hook
) (interface
);
1138 /* remove the io object */
1139 omapi_unregister_io_object ((omapi_object_t
*)interface
);
1141 if_deregister_send (interface
);
1142 if_deregister_receive (interface
);
1144 return ISC_R_SUCCESS
;
1147 void interface_stash (struct interface_info
*tptr
)
1149 struct interface_info
**vec
;
1152 /* If the registerer didn't assign an index, assign one now. */
1153 if (tptr
-> index
== -1) {
1154 tptr
-> index
= interface_count
++;
1155 while (tptr
-> index
< interface_max
&&
1156 interface_vector
[tptr
-> index
])
1157 tptr
-> index
= interface_count
++;
1160 if (interface_max
<= tptr
-> index
) {
1161 delta
= tptr
-> index
- interface_max
+ 10;
1162 vec
= dmalloc ((interface_max
+ delta
) *
1163 sizeof (struct interface_info
*), MDL
);
1166 memset (&vec
[interface_max
], 0,
1167 (sizeof (struct interface_info
*)) * delta
);
1168 interface_max
+= delta
;
1169 if (interface_vector
) {
1170 memcpy (vec
, interface_vector
,
1172 sizeof (struct interface_info
*)));
1173 dfree (interface_vector
, MDL
);
1175 interface_vector
= vec
;
1177 interface_reference (&interface_vector
[tptr
-> index
], tptr
, MDL
);
1178 if (tptr
-> index
>= interface_count
)
1179 interface_count
= tptr
-> index
+ 1;
1180 #if defined (TRACING)
1181 trace_interface_register (interface_trace
, tptr
);
1185 void interface_snorf (struct interface_info
*tmp
, int ir
)
1187 tmp
-> circuit_id
= (u_int8_t
*)tmp
-> name
;
1188 tmp
-> circuit_id_len
= strlen (tmp
-> name
);
1189 tmp
-> remote_id
= 0;
1190 tmp
-> remote_id_len
= 0;
1193 interface_reference (&tmp
-> next
,
1195 interface_dereference (&interfaces
, MDL
);
1197 interface_reference (&interfaces
, tmp
, MDL
);