3 Network input dispatcher... */
6 * Copyright (c) 2004-2006 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.49 2006/02/24 23:16:28 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
41 #include <sys/ioctl.h>
43 struct interface_info
*interfaces
, *dummy_interfaces
, *fallback_interface
;
44 int interfaces_invalidated
;
45 int quiet_interface_discovery
;
47 u_int16_t remote_port
;
48 int (*dhcp_interface_setup_hook
) (struct interface_info
*, struct iaddr
*);
49 int (*dhcp_interface_discovery_hook
) (struct interface_info
*);
50 isc_result_t (*dhcp_interface_startup_hook
) (struct interface_info
*);
51 int (*dhcp_interface_shutdown_hook
) (struct interface_info
*);
53 struct in_addr limited_broadcast
;
54 struct in_addr local_address
;
56 void (*bootp_packet_handler
) PROTO ((struct interface_info
*,
57 struct dhcp_packet
*, unsigned,
59 struct iaddr
, struct hardware
*));
61 omapi_object_type_t
*dhcp_type_interface
;
63 trace_type_t
*interface_trace
;
64 trace_type_t
*inpacket_trace
;
65 trace_type_t
*outpacket_trace
;
67 struct interface_info
**interface_vector
;
71 OMAPI_OBJECT_ALLOC (interface
, struct interface_info
, dhcp_type_interface
)
73 isc_result_t
interface_setup ()
76 status
= omapi_object_type_register (&dhcp_type_interface
,
78 dhcp_interface_set_value
,
79 dhcp_interface_get_value
,
80 dhcp_interface_destroy
,
81 dhcp_interface_signal_handler
,
82 dhcp_interface_stuff_values
,
83 dhcp_interface_lookup
,
84 dhcp_interface_create
,
85 dhcp_interface_remove
,
87 sizeof (struct interface_info
),
88 interface_initialize
, RC_MISC
);
89 if (status
!= ISC_R_SUCCESS
)
90 log_fatal ("Can't register interface object type: %s",
91 isc_result_totext (status
));
97 void interface_trace_setup ()
99 interface_trace
= trace_type_register ("interface", (void *)0,
100 trace_interface_input
,
101 trace_interface_stop
, MDL
);
102 inpacket_trace
= trace_type_register ("inpacket", (void *)0,
103 trace_inpacket_input
,
104 trace_inpacket_stop
, MDL
);
105 outpacket_trace
= trace_type_register ("outpacket", (void *)0,
106 trace_outpacket_input
,
107 trace_outpacket_stop
, MDL
);
111 isc_result_t
interface_initialize (omapi_object_t
*ipo
,
112 const char *file
, int line
)
114 struct interface_info
*ip
= (struct interface_info
*)ipo
;
115 ip
-> rfdesc
= ip
-> wfdesc
= -1;
116 return ISC_R_SUCCESS
;
119 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
120 For each interface that's of type INET and not the loopback interface,
121 register that interface with the network I/O software, figure out what
122 subnet it's on, and add it to the list of interfaces. */
124 void discover_interfaces (state
)
127 struct interface_info
*tmp
, *ip
;
128 struct interface_info
*last
, *next
;
134 int address_count
= 0;
135 struct subnet
*subnet
;
136 struct shared_network
*share
;
137 struct sockaddr_in foo
;
140 #ifdef ALIAS_NAMES_PERMUTED
144 static int setup_fallback
= 0;
147 /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
148 if ((sock
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) < 0)
149 log_fatal ("Can't create addrlist socket");
151 /* Get the interface configuration information... */
153 #ifdef SIOCGIFCONF_ZERO_PROBE
154 /* linux will only tell us how long a buffer it wants if we give it
155 * a null buffer first. So, do a dry run to figure out the length.
157 * XXX this code is duplicated from below because trying to fold
158 * the logic into the if statement and goto resulted in excesssive
159 * obfuscation. The intent is that unless you run Linux you shouldn't
160 * have to deal with this. */
163 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)NULL
;
165 /* otherwise, we just feed it a starting size, and it'll tell us if
168 ic
.ifc_len
= sizeof buf
;
169 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)buf
;
173 i
= ioctl(sock
, SIOCGIFCONF
, &ic
);
176 log_fatal ("ioctl: SIOCGIFCONF: %m");
178 #ifdef SIOCGIFCONF_ZERO_PROBE
179 /* Workaround for SIOCGIFCONF bug on some Linux versions. */
180 if (ic
.ifc_ifcu
.ifcu_buf
== 0 && ic
.ifc_len
== 0) {
181 ic
.ifc_len
= sizeof buf
;
182 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)buf
;
187 /* If the SIOCGIFCONF resulted in more data than would fit in
188 a buffer, allocate a bigger buffer. */
189 if ((ic
.ifc_ifcu
.ifcu_buf
== buf
190 #ifdef SIOCGIFCONF_ZERO_PROBE
191 || ic
.ifc_ifcu
.ifcu_buf
== 0
193 ) && ic
.ifc_len
> sizeof buf
) {
194 ic
.ifc_ifcu
.ifcu_buf
= dmalloc ((size_t)ic
.ifc_len
, MDL
);
195 if (!ic
.ifc_ifcu
.ifcu_buf
)
196 log_fatal ("Can't allocate SIOCGIFCONF buffer.");
198 #ifdef SIOCGIFCONF_ZERO_PROBE
199 } else if (ic
.ifc_ifcu
.ifcu_buf
== 0) {
200 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)buf
;
201 ic
.ifc_len
= sizeof buf
;
207 /* If we already have a list of interfaces, and we're running as
208 a DHCP server, the interfaces were requested. */
209 if (interfaces
&& (state
== DISCOVER_SERVER
||
210 state
== DISCOVER_RELAY
||
211 state
== DISCOVER_REQUESTED
))
213 else if (state
== DISCOVER_UNCONFIGURED
)
214 ir
= INTERFACE_REQUESTED
| INTERFACE_AUTOMATIC
;
216 ir
= INTERFACE_REQUESTED
;
218 /* Cycle through the list of interfaces looking for IP addresses. */
219 for (i
= 0; i
< ic
.ifc_len
;) {
220 struct ifreq
*ifp
= (struct ifreq
*)((caddr_t
)ic
.ifc_req
+ i
);
222 if (ifp
-> ifr_addr
.sa_len
> sizeof (struct sockaddr
))
223 i
+= (sizeof ifp
-> ifr_name
) + ifp
-> ifr_addr
.sa_len
;
228 #ifdef ALIAS_NAMES_PERMUTED
229 if ((s
= strrchr (ifp
-> ifr_name
, ':'))) {
234 #ifdef SKIP_DUMMY_INTERFACES
235 if (!strncmp (ifp
-> ifr_name
, "dummy", 5))
240 /* See if this is the sort of interface we want to
242 strcpy (ifr
.ifr_name
, ifp
-> ifr_name
);
243 if (ioctl (sock
, SIOCGIFFLAGS
, &ifr
) < 0)
244 log_fatal ("Can't get interface flags for %s: %m",
247 /* See if we've seen an interface that matches this one. */
248 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
)
249 if (!strcmp (tmp
-> name
, ifp
-> ifr_name
))
252 /* Skip non broadcast interfaces (plus loopback and
253 point-to-point in case an OS incorrectly marks them
254 as broadcast). Also skip down interfaces unless we're
255 trying to get a list of configurable interfaces. */
256 if (((!(ifr
.ifr_flags
& IFF_BROADCAST
) ||
257 ifr
.ifr_flags
& IFF_LOOPBACK
||
258 ifr
.ifr_flags
& IFF_POINTOPOINT
) && !tmp
) ||
259 (!(ifr
.ifr_flags
& IFF_UP
) &&
260 state
!= DISCOVER_UNCONFIGURED
))
263 /* If there isn't already an interface by this name,
266 tmp
= (struct interface_info
*)0;
267 status
= interface_allocate (&tmp
, MDL
);
268 if (status
!= ISC_R_SUCCESS
)
269 log_fatal ("Error allocating interface %s: %s",
271 isc_result_totext (status
));
272 strcpy (tmp
-> name
, ifp
-> ifr_name
);
273 interface_snorf (tmp
, ir
);
274 interface_dereference (&tmp
, MDL
);
275 tmp
= interfaces
; /* XXX */
278 if (dhcp_interface_discovery_hook
)
279 (*dhcp_interface_discovery_hook
) (tmp
);
281 /* If we have the capability, extract link information
282 and record it in a linked list. */
284 if (ifp
-> ifr_addr
.sa_family
== AF_LINK
) {
285 struct sockaddr_dl
*foo
= ((struct sockaddr_dl
*)
287 #if defined (HAVE_SIN_LEN)
288 tmp
-> hw_address
.hlen
= foo
-> sdl_alen
;
290 tmp
-> hw_address
.hlen
= 6; /* XXX!!! */
292 tmp
-> hw_address
.hbuf
[0] = HTYPE_ETHER
; /* XXX */
293 memcpy (&tmp
-> hw_address
.hbuf
[1],
294 LLADDR (foo
), tmp
-> hw_address
.hlen
);
295 tmp
-> hw_address
.hlen
++; /* for type. */
299 if (ifp
-> ifr_addr
.sa_family
== AF_INET
) {
302 /* Get a pointer to the address... */
303 memcpy (&foo
, &ifp
-> ifr_addr
,
304 sizeof ifp
-> ifr_addr
);
306 /* We don't want the loopback interface. */
307 if (foo
.sin_addr
.s_addr
== htonl (INADDR_LOOPBACK
) &&
308 ((tmp
-> flags
& INTERFACE_AUTOMATIC
) &&
309 state
== DISCOVER_SERVER
))
313 /* If this is the first real IP address we've
314 found, keep a pointer to ifreq structure in
315 which we found it. */
318 unsigned len
= ((sizeof ifp
-> ifr_name
) +
319 ifp
-> ifr_addr
.sa_len
);
321 unsigned len
= sizeof *ifp
;
323 tif
= (struct ifreq
*)dmalloc (len
, MDL
);
325 log_fatal ("no space for ifp.");
326 memcpy (tif
, ifp
, len
);
328 tmp
-> primary_address
= foo
.sin_addr
;
331 /* Grab the address... */
333 memcpy (addr
.iabuf
, &foo
.sin_addr
.s_addr
,
335 if (dhcp_interface_setup_hook
)
336 (*dhcp_interface_setup_hook
) (tmp
, &addr
);
340 /* If we allocated a buffer, free it. */
341 if (ic
.ifc_ifcu
.ifcu_buf
!= buf
)
342 dfree (ic
.ifc_ifcu
.ifcu_buf
, MDL
);
344 #if defined (LINUX_SLASHPROC_DISCOVERY)
345 /* On Linux, interfaces that don't have IP addresses don't
346 show up in the SIOCGIFCONF syscall. This only matters for
347 the DHCP client, of course - the relay agent and server
348 should only care about interfaces that are configured with
351 The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
352 that, when read, prints a human readable network status. We
353 extract the names of the network devices by skipping the first
354 two lines (which are header) and then parsing off everything
355 up to the colon in each subsequent line - these lines start
356 with the interface name, then a colon, then a bunch of
359 if (state
== DISCOVER_UNCONFIGURED
) {
364 proc_dev
= fopen (PROCDEV_DEVICE
, "r");
366 log_fatal ("%s: %m", PROCDEV_DEVICE
);
368 while (fgets (buffer
, sizeof buffer
, proc_dev
)) {
372 /* Skip the first two blocks, which are header
379 sep
= strrchr (buffer
, ':');
385 /* See if we've seen an interface that matches
387 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
)
388 if (!strcmp (tmp
-> name
, name
))
391 /* If we found one, nothing more to do.. */
395 strncpy (ifr
.ifr_name
, name
, IFNAMSIZ
);
397 /* Skip non broadcast interfaces (plus loopback and
398 * point-to-point in case an OS incorrectly marks them
401 if ((ioctl (sock
, SIOCGIFFLAGS
, &ifr
) < 0) ||
402 (!(ifr
.ifr_flags
& IFF_BROADCAST
)) ||
403 (ifr
.ifr_flags
& IFF_LOOPBACK
) ||
404 (ifr
.ifr_flags
& IFF_POINTOPOINT
))
407 /* Otherwise, allocate one. */
408 tmp
= (struct interface_info
*)0;
409 status
= interface_allocate (&tmp
, MDL
);
410 if (status
!= ISC_R_SUCCESS
)
411 log_fatal ("Can't allocate interface %s: %s",
412 name
, isc_result_totext (status
));
414 strncpy (tmp
-> name
, name
, IFNAMSIZ
);
416 interface_reference (&tmp
-> next
,
418 interface_dereference (&interfaces
, MDL
);
420 interface_reference (&interfaces
, tmp
, MDL
);
421 interface_dereference (&tmp
, MDL
);
424 if (dhcp_interface_discovery_hook
)
425 (*dhcp_interface_discovery_hook
) (tmp
);
432 /* Now cycle through all the interfaces we found, looking for
433 hardware addresses. */
434 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
435 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
) {
441 /* Make up an ifreq structure. */
442 tif
= (struct ifreq
*)dmalloc (sizeof (struct ifreq
),
445 log_fatal ("no space to remember ifp.");
446 memset (tif
, 0, sizeof (struct ifreq
));
447 strcpy (tif
-> ifr_name
, tmp
-> name
);
451 /* Read the hardware address from this interface. */
453 if (ioctl (sock
, SIOCGIFHWADDR
, &ifr
) < 0)
456 sa
= *(struct sockaddr
*)&ifr
.ifr_hwaddr
;
458 switch (sa
.sa_family
) {
459 #ifdef HAVE_ARPHRD_TUNNEL
461 /* ignore tunnel interfaces. */
463 #ifdef HAVE_ARPHRD_ROSE
466 #ifdef HAVE_ARPHRD_IRDA
468 /* ignore infrared interfaces. */
470 #ifdef HAVE_ARPHRD_SIT
472 /* ignore IPv6-in-IPv4 interfaces. */
474 #ifdef HAVE_ARPHRD_IEEE1394
475 case ARPHRD_IEEE1394
:
476 /* ignore IEEE1394 interfaces. */
478 #ifdef HAVE_ARPHRD_LOOPBACK
479 case ARPHRD_LOOPBACK
:
480 /* ignore loopback interface */
485 tmp
-> hw_address
.hlen
= 7;
486 tmp
-> hw_address
.hbuf
[0] = ARPHRD_ETHER
;
487 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
490 #ifndef HAVE_ARPHRD_IEEE802
491 # define ARPHRD_IEEE802 HTYPE_IEEE802
493 #if defined (HAVE_ARPHRD_IEEE802_TR)
494 case ARPHRD_IEEE802_TR
:
497 tmp
-> hw_address
.hlen
= 7;
498 tmp
-> hw_address
.hbuf
[0] = ARPHRD_IEEE802
;
499 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
502 #ifndef HAVE_ARPHRD_FDDI
503 # define ARPHRD_FDDI HTYPE_FDDI
506 tmp
-> hw_address
.hlen
= 17;
507 tmp
-> hw_address
.hbuf
[0] = HTYPE_FDDI
; /* XXX */
508 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 16);
511 #ifdef HAVE_ARPHRD_METRICOM
512 case ARPHRD_METRICOM
:
513 tmp
-> hw_address
.hlen
= 7;
514 tmp
-> hw_address
.hbuf
[0] = ARPHRD_METRICOM
;
515 memcpy (&tmp
-> hw_address
.hbuf
[0], sa
.sa_data
, 6);
519 #ifdef HAVE_ARPHRD_AX25
521 tmp
-> hw_address
.hlen
= 7;
522 tmp
-> hw_address
.hbuf
[0] = ARPHRD_AX25
;
523 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
527 #ifdef HAVE_ARPHRD_NETROM
529 tmp
-> hw_address
.hlen
= 7;
530 tmp
-> hw_address
.hbuf
[0] = ARPHRD_NETROM
;
531 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
536 log_error ("%s: unknown hardware address type %d",
537 ifr
.ifr_name
, sa
.sa_family
);
541 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
543 /* If we're just trying to get a list of interfaces that we might
544 be able to configure, we can quit now. */
545 if (state
== DISCOVER_UNCONFIGURED
) {
550 /* Weed out the interfaces that did not have IP addresses. */
551 tmp
= last
= next
= (struct interface_info
*)0;
553 interface_reference (&tmp
, interfaces
, MDL
);
556 interface_dereference (&next
, MDL
);
558 interface_reference (&next
, tmp
-> next
, MDL
);
559 /* skip interfaces that are running already */
560 if (tmp
-> flags
& INTERFACE_RUNNING
) {
561 interface_dereference(&tmp
, MDL
);
563 interface_reference(&tmp
, next
, MDL
);
566 if ((tmp
-> flags
& INTERFACE_AUTOMATIC
) &&
567 state
== DISCOVER_REQUESTED
)
568 tmp
-> flags
&= ~(INTERFACE_AUTOMATIC
|
569 INTERFACE_REQUESTED
);
570 if (!tmp
-> ifp
|| !(tmp
-> flags
& INTERFACE_REQUESTED
)) {
571 if ((tmp
-> flags
& INTERFACE_REQUESTED
) != ir
)
572 log_fatal ("%s: not found", tmp
-> name
);
575 interface_dereference (&interfaces
,
578 interface_reference (&interfaces
, next
, MDL
);
580 interface_dereference (&last
-> next
, MDL
);
582 interface_reference (&last
-> next
,
586 interface_dereference (&tmp
-> next
, MDL
);
588 /* Remember the interface in case we need to know
590 if (dummy_interfaces
) {
591 interface_reference (&tmp
-> next
,
592 dummy_interfaces
, MDL
);
593 interface_dereference (&dummy_interfaces
, MDL
);
595 interface_reference (&dummy_interfaces
, tmp
, MDL
);
596 interface_dereference (&tmp
, MDL
);
598 interface_reference (&tmp
, next
, MDL
);
603 memcpy (&foo
, &tmp
-> ifp
-> ifr_addr
,
604 sizeof tmp
-> ifp
-> ifr_addr
);
606 /* We must have a subnet declaration for each interface. */
607 if (!tmp
-> shared_network
&& (state
== DISCOVER_SERVER
)) {
608 log_error ("%s", "");
609 log_error ("No subnet declaration for %s (%s).",
610 tmp
-> name
, inet_ntoa (foo
.sin_addr
));
611 if (supports_multiple_interfaces (tmp
)) {
612 log_error ("** Ignoring requests on %s. %s",
613 tmp
-> name
, "If this is not what");
614 log_error (" you want, please write %s",
615 "a subnet declaration");
616 log_error (" in your dhcpd.conf file %s",
617 "for the network segment");
618 log_error (" to %s %s %s",
620 tmp
-> name
, "is attached. **");
621 log_error ("%s", "");
624 log_error ("You must write a subnet %s",
625 " declaration for this");
626 log_error ("subnet. You cannot prevent %s",
628 log_error ("from listening on this subnet %s",
630 log_fatal ("operating system does not %s.",
631 "support this capability");
635 /* Find subnets that don't have valid interface
637 for (subnet
= (tmp
-> shared_network
638 ? tmp
-> shared_network
-> subnets
639 : (struct subnet
*)0);
640 subnet
; subnet
= subnet
-> next_sibling
) {
641 if (!subnet
-> interface_address
.len
) {
642 /* Set the interface address for this subnet
643 to the first address we found. */
644 subnet
-> interface_address
.len
= 4;
645 memcpy (subnet
-> interface_address
.iabuf
,
646 &foo
.sin_addr
.s_addr
, 4);
650 /* Flag the index as not having been set, so that the
651 interface registerer can set it or not as it chooses. */
654 /* Register the interface... */
655 if_register_receive (tmp
);
656 if_register_send (tmp
);
658 interface_stash (tmp
);
660 #if defined (HAVE_SETFD)
661 if (fcntl (tmp
-> rfdesc
, F_SETFD
, 1) < 0)
662 log_error ("Can't set close-on-exec on %s: %m",
664 if (tmp
-> rfdesc
!= tmp
-> wfdesc
) {
665 if (fcntl (tmp
-> wfdesc
, F_SETFD
, 1) < 0)
666 log_error ("Can't set close-on-exec on %s: %m",
671 interface_dereference (&tmp
, MDL
);
673 interface_reference (&tmp
, next
, MDL
);
676 /* Now register all the remaining interfaces as protocols. */
677 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
) {
678 /* not if it's been registered before */
679 if (tmp
-> flags
& INTERFACE_RUNNING
)
681 if (tmp
-> rfdesc
== -1)
683 status
= omapi_register_io_object ((omapi_object_t
*)tmp
,
686 if (status
!= ISC_R_SUCCESS
)
687 log_fatal ("Can't register I/O handle for %s: %s",
688 tmp
-> name
, isc_result_totext (status
));
693 if (state
== DISCOVER_SERVER
&& wifcount
== 0) {
695 log_fatal ("Not configured to listen on any interfaces!");
698 if (!setup_fallback
) {
700 maybe_setup_fallback ();
703 #if defined (HAVE_SETFD)
704 if (fallback_interface
) {
705 if (fcntl (fallback_interface
-> rfdesc
, F_SETFD
, 1) < 0)
706 log_error ("Can't set close-on-exec on fallback: %m");
707 if (fallback_interface
-> rfdesc
!= fallback_interface
-> wfdesc
) {
708 if (fcntl (fallback_interface
-> wfdesc
, F_SETFD
, 1) < 0)
709 log_error ("Can't set close-on-exec on fallback: %m");
715 int if_readsocket (h
)
718 struct interface_info
*ip
;
720 if (h
-> type
!= dhcp_type_interface
)
722 ip
= (struct interface_info
*)h
;
726 int setup_fallback (struct interface_info
**fp
, const char *file
, int line
)
730 status
= interface_allocate (&fallback_interface
, file
, line
);
731 if (status
!= ISC_R_SUCCESS
)
732 log_fatal ("Error allocating fallback interface: %s",
733 isc_result_totext (status
));
734 strcpy (fallback_interface
-> name
, "fallback");
735 if (dhcp_interface_setup_hook
)
736 (*dhcp_interface_setup_hook
) (fallback_interface
,
738 status
= interface_reference (fp
, fallback_interface
, file
, line
);
740 fallback_interface
-> index
= -1;
741 interface_stash (fallback_interface
);
742 return status
== ISC_R_SUCCESS
;
745 void reinitialize_interfaces ()
747 struct interface_info
*ip
;
749 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
750 if_reinitialize_receive (ip
);
751 if_reinitialize_send (ip
);
754 if (fallback_interface
)
755 if_reinitialize_send (fallback_interface
);
757 interfaces_invalidated
= 1;
760 isc_result_t
got_one (h
)
763 struct sockaddr_in from
;
764 struct hardware hfrom
;
768 unsigned char packbuf
[4095]; /* Packet input buffer.
769 Must be as large as largest
771 struct dhcp_packet packet
;
773 struct interface_info
*ip
;
775 if (h
-> type
!= dhcp_type_interface
)
776 return ISC_R_INVALIDARG
;
777 ip
= (struct interface_info
*)h
;
781 receive_packet (ip
, u
.packbuf
, sizeof u
, &from
, &hfrom
)) < 0) {
782 log_error ("receive_packet failed on %s: %m", ip
-> name
);
783 return ISC_R_UNEXPECTED
;
786 return ISC_R_UNEXPECTED
;
788 /* If we didn't at least get the fixed portion of the BOOTP
789 packet, drop the packet. We're allowing packets with no
790 sname or filename, because we're aware of at least one
791 client that sends such packets, but this definitely falls
792 into the category of being forgiving. */
793 if (result
< DHCP_FIXED_NON_UDP
- DHCP_SNAME_LEN
- DHCP_FILE_LEN
)
794 return ISC_R_UNEXPECTED
;
796 if (bootp_packet_handler
) {
798 memcpy (ifrom
.iabuf
, &from
.sin_addr
, ifrom
.len
);
800 (*bootp_packet_handler
) (ip
, &u
.packet
, (unsigned)result
,
801 from
.sin_port
, ifrom
, &hfrom
);
804 /* If there is buffered data, read again. This is for, e.g.,
805 bpf, which may return two packets at once. */
806 if (ip
-> rbuf_offset
!= ip
-> rbuf_len
)
808 return ISC_R_SUCCESS
;
811 isc_result_t
dhcp_interface_set_value (omapi_object_t
*h
,
813 omapi_data_string_t
*name
,
814 omapi_typed_data_t
*value
)
816 struct interface_info
*interface
;
820 if (h
-> type
!= dhcp_type_interface
)
821 return ISC_R_INVALIDARG
;
822 interface
= (struct interface_info
*)h
;
824 if (!omapi_ds_strcmp (name
, "name")) {
825 if ((value
-> type
== omapi_datatype_data
||
826 value
-> type
== omapi_datatype_string
) &&
827 value
-> u
.buffer
.len
< sizeof interface
-> name
) {
828 memcpy (interface
-> name
,
829 value
-> u
.buffer
.value
,
830 value
-> u
.buffer
.len
);
831 interface
-> name
[value
-> u
.buffer
.len
] = 0;
833 return ISC_R_INVALIDARG
;
834 return ISC_R_SUCCESS
;
837 /* Try to find some inner object that can take the value. */
838 if (h
-> inner
&& h
-> inner
-> type
-> set_value
) {
839 status
= ((*(h
-> inner
-> type
-> set_value
))
840 (h
-> inner
, id
, name
, value
));
841 if (status
== ISC_R_SUCCESS
|| status
== ISC_R_UNCHANGED
)
845 return ISC_R_NOTFOUND
;
849 isc_result_t
dhcp_interface_get_value (omapi_object_t
*h
,
851 omapi_data_string_t
*name
,
852 omapi_value_t
**value
)
854 return ISC_R_NOTIMPLEMENTED
;
857 isc_result_t
dhcp_interface_destroy (omapi_object_t
*h
,
858 const char *file
, int line
)
860 struct interface_info
*interface
;
863 if (h
-> type
!= dhcp_type_interface
)
864 return ISC_R_INVALIDARG
;
865 interface
= (struct interface_info
*)h
;
867 if (interface
-> ifp
) {
868 dfree (interface
-> ifp
, file
, line
);
869 interface
-> ifp
= 0;
871 if (interface
-> next
)
872 interface_dereference (&interface
-> next
, file
, line
);
873 if (interface
-> rbuf
) {
874 dfree (interface
-> rbuf
, file
, line
);
875 interface
-> rbuf
= (unsigned char *)0;
877 if (interface
-> client
)
878 interface
-> client
= (struct client_state
*)0;
880 if (interface
-> shared_network
)
881 omapi_object_dereference ((omapi_object_t
**)
882 &interface
-> shared_network
, MDL
);
884 return ISC_R_SUCCESS
;
887 isc_result_t
dhcp_interface_signal_handler (omapi_object_t
*h
,
888 const char *name
, va_list ap
)
890 struct interface_info
*ip
, *interface
;
891 struct client_config
*config
;
892 struct client_state
*client
;
895 if (h
-> type
!= dhcp_type_interface
)
896 return ISC_R_INVALIDARG
;
897 interface
= (struct interface_info
*)h
;
899 /* If it's an update signal, see if the interface is dead right
900 now, or isn't known at all, and if that's the case, revive it. */
901 if (!strcmp (name
, "update")) {
902 for (ip
= dummy_interfaces
; ip
; ip
= ip
-> next
)
905 if (ip
&& dhcp_interface_startup_hook
)
906 return (*dhcp_interface_startup_hook
) (ip
);
908 for (ip
= interfaces
; ip
; ip
= ip
-> next
)
911 if (!ip
&& dhcp_interface_startup_hook
)
912 return (*dhcp_interface_startup_hook
) (ip
);
915 /* Try to find some inner object that can take the value. */
916 if (h
-> inner
&& h
-> inner
-> type
-> get_value
) {
917 status
= ((*(h
-> inner
-> type
-> signal_handler
))
918 (h
-> inner
, name
, ap
));
919 if (status
== ISC_R_SUCCESS
)
922 return ISC_R_NOTFOUND
;
925 isc_result_t
dhcp_interface_stuff_values (omapi_object_t
*c
,
929 struct interface_info
*interface
;
932 if (h
-> type
!= dhcp_type_interface
)
933 return ISC_R_INVALIDARG
;
934 interface
= (struct interface_info
*)h
;
936 /* Write out all the values. */
938 status
= omapi_connection_put_name (c
, "state");
939 if (status
!= ISC_R_SUCCESS
)
941 if (interface
-> flags
&& INTERFACE_REQUESTED
)
942 status
= omapi_connection_put_string (c
, "up");
944 status
= omapi_connection_put_string (c
, "down");
945 if (status
!= ISC_R_SUCCESS
)
948 /* Write out the inner object, if any. */
949 if (h
-> inner
&& h
-> inner
-> type
-> stuff_values
) {
950 status
= ((*(h
-> inner
-> type
-> stuff_values
))
951 (c
, id
, h
-> inner
));
952 if (status
== ISC_R_SUCCESS
)
956 return ISC_R_SUCCESS
;
959 isc_result_t
dhcp_interface_lookup (omapi_object_t
**ip
,
963 omapi_value_t
*tv
= (omapi_value_t
*)0;
965 struct interface_info
*interface
;
970 /* First see if we were sent a handle. */
971 status
= omapi_get_value_str (ref
, id
, "handle", &tv
);
972 if (status
== ISC_R_SUCCESS
) {
973 status
= omapi_handle_td_lookup (ip
, tv
-> value
);
975 omapi_value_dereference (&tv
, MDL
);
976 if (status
!= ISC_R_SUCCESS
)
979 /* Don't return the object if the type is wrong. */
980 if ((*ip
) -> type
!= dhcp_type_interface
) {
981 omapi_object_dereference (ip
, MDL
);
982 return ISC_R_INVALIDARG
;
986 /* Now look for an interface name. */
987 status
= omapi_get_value_str (ref
, id
, "name", &tv
);
988 if (status
== ISC_R_SUCCESS
) {
991 for (interface
= interfaces
; interface
;
992 interface
= interface
-> next
) {
993 s
= memchr (interface
-> name
, 0, IFNAMSIZ
);
995 len
= s
- &interface
-> name
[0];
998 if ((tv
-> value
-> u
.buffer
.len
== len
&&
999 !memcmp (interface
-> name
,
1000 (char *)tv
-> value
-> u
.buffer
.value
,
1005 for (interface
= dummy_interfaces
;
1006 interface
; interface
= interface
-> next
) {
1007 s
= memchr (interface
-> name
, 0, IFNAMSIZ
);
1009 len
= s
- &interface
-> name
[0];
1012 if ((tv
-> value
-> u
.buffer
.len
== len
&&
1013 !memcmp (interface
-> name
,
1015 tv
-> value
-> u
.buffer
.value
,
1021 omapi_value_dereference (&tv
, MDL
);
1022 if (*ip
&& *ip
!= (omapi_object_t
*)interface
) {
1023 omapi_object_dereference (ip
, MDL
);
1024 return ISC_R_KEYCONFLICT
;
1025 } else if (!interface
) {
1027 omapi_object_dereference (ip
, MDL
);
1028 return ISC_R_NOTFOUND
;
1030 omapi_object_reference (ip
,
1031 (omapi_object_t
*)interface
,
1035 /* If we get to here without finding an interface, no valid key was
1038 return ISC_R_NOKEYS
;
1039 return ISC_R_SUCCESS
;
1042 /* actually just go discover the interface */
1043 isc_result_t
dhcp_interface_create (omapi_object_t
**lp
,
1046 struct interface_info
*hp
;
1047 isc_result_t status
;
1049 hp
= (struct interface_info
*)0;
1050 status
= interface_allocate (&hp
, MDL
);
1051 if (status
!= ISC_R_SUCCESS
)
1053 hp
-> flags
= INTERFACE_REQUESTED
;
1054 status
= interface_reference ((struct interface_info
**)lp
, hp
, MDL
);
1055 interface_dereference (&hp
, MDL
);
1059 isc_result_t
dhcp_interface_remove (omapi_object_t
*lp
,
1062 struct interface_info
*interface
, *ip
, *last
;
1064 interface
= (struct interface_info
*)lp
;
1066 /* remove from interfaces */
1068 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
1069 if (ip
== interface
) {
1071 interface_dereference (&last
-> next
, MDL
);
1073 interface_reference (&last
-> next
,
1076 interface_dereference (&interfaces
, MDL
);
1078 interface_reference (&interfaces
,
1082 interface_dereference (&ip
-> next
, MDL
);
1088 return ISC_R_NOTFOUND
;
1090 /* add the interface to the dummy_interface list */
1091 if (dummy_interfaces
) {
1092 interface_reference (&interface
-> next
,
1093 dummy_interfaces
, MDL
);
1094 interface_dereference (&dummy_interfaces
, MDL
);
1096 interface_reference (&dummy_interfaces
, interface
, MDL
);
1098 /* do a DHCPRELEASE */
1099 if (dhcp_interface_shutdown_hook
)
1100 (*dhcp_interface_shutdown_hook
) (interface
);
1102 /* remove the io object */
1103 omapi_unregister_io_object ((omapi_object_t
*)interface
);
1105 if_deregister_send (interface
);
1106 if_deregister_receive (interface
);
1108 return ISC_R_SUCCESS
;
1111 void interface_stash (struct interface_info
*tptr
)
1113 struct interface_info
**vec
;
1116 /* If the registerer didn't assign an index, assign one now. */
1117 if (tptr
-> index
== -1) {
1118 tptr
-> index
= interface_count
++;
1119 while (tptr
-> index
< interface_max
&&
1120 interface_vector
[tptr
-> index
])
1121 tptr
-> index
= interface_count
++;
1124 if (interface_max
<= tptr
-> index
) {
1125 delta
= tptr
-> index
- interface_max
+ 10;
1126 vec
= dmalloc ((interface_max
+ delta
) *
1127 sizeof (struct interface_info
*), MDL
);
1130 memset (&vec
[interface_max
], 0,
1131 (sizeof (struct interface_info
*)) * delta
);
1132 interface_max
+= delta
;
1133 if (interface_vector
) {
1134 memcpy (vec
, interface_vector
,
1136 sizeof (struct interface_info
*)));
1137 dfree (interface_vector
, MDL
);
1139 interface_vector
= vec
;
1141 interface_reference (&interface_vector
[tptr
-> index
], tptr
, MDL
);
1142 if (tptr
-> index
>= interface_count
)
1143 interface_count
= tptr
-> index
+ 1;
1144 #if defined (TRACING)
1145 trace_interface_register (interface_trace
, tptr
);
1149 void interface_snorf (struct interface_info
*tmp
, int ir
)
1151 tmp
-> circuit_id
= (u_int8_t
*)tmp
-> name
;
1152 tmp
-> circuit_id_len
= strlen (tmp
-> name
);
1153 tmp
-> remote_id
= 0;
1154 tmp
-> remote_id_len
= 0;
1157 interface_reference (&tmp
-> next
,
1159 interface_dereference (&interfaces
, MDL
);
1161 interface_reference (&interfaces
, tmp
, MDL
);