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$ Copyright (c) 2004-2005 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
;
128 // struct interface_info *ip;
129 struct interface_info
*last
, *next
;
135 // int address_count = 0;
136 struct subnet
*subnet
;
137 // struct shared_network *share;
138 struct sockaddr_in foo
;
141 #ifdef ALIAS_NAMES_PERMUTED
145 static int setup_fallback
= 0;
148 /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
149 if ((sock
= socket (AF_INET
, SOCK_DGRAM
, IPPROTO_UDP
)) < 0)
150 log_fatal ("Can't create addrlist socket");
152 /* Get the interface configuration information... */
154 #ifdef SIOCGIFCONF_ZERO_PROBE
155 /* linux will only tell us how long a buffer it wants if we give it
156 * a null buffer first. So, do a dry run to figure out the length.
158 * XXX this code is duplicated from below because trying to fold
159 * the logic into the if statement and goto resulted in excesssive
160 * obfuscation. The intent is that unless you run Linux you shouldn't
161 * have to deal with this. */
164 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)NULL
;
166 /* otherwise, we just feed it a starting size, and it'll tell us if
169 ic
.ifc_len
= sizeof buf
;
170 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)buf
;
174 #ifdef SOCKET_IS_NOT_A_FILE
175 i
= IoctlSocket(sock
, SIOCGIFCONF
, (char *)&ic
);
177 i
= ioctl(sock
, SIOCGIFCONF
, &ic
);
181 log_fatal ("ioctl: SIOCGIFCONF: %m");
183 #ifdef SIOCGIFCONF_ZERO_PROBE
184 /* Workaround for SIOCGIFCONF bug on some Linux versions. */
185 if (ic
.ifc_ifcu
.ifcu_buf
== 0 && ic
.ifc_len
== 0) {
186 ic
.ifc_len
= sizeof buf
;
187 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)buf
;
192 /* If the SIOCGIFCONF resulted in more data than would fit in
193 a buffer, allocate a bigger buffer. */
194 if ((ic
.ifc_ifcu
.ifcu_buf
== buf
195 #ifdef SIOCGIFCONF_ZERO_PROBE
196 || ic
.ifc_ifcu
.ifcu_buf
== 0
198 ) && ic
.ifc_len
> sizeof buf
) {
199 ic
.ifc_ifcu
.ifcu_buf
= dmalloc ((size_t)ic
.ifc_len
, MDL
);
200 if (!ic
.ifc_ifcu
.ifcu_buf
)
201 log_fatal ("Can't allocate SIOCGIFCONF buffer.");
203 #ifdef SIOCGIFCONF_ZERO_PROBE
204 } else if (ic
.ifc_ifcu
.ifcu_buf
== 0) {
205 ic
.ifc_ifcu
.ifcu_buf
= (caddr_t
)buf
;
206 ic
.ifc_len
= sizeof buf
;
212 /* If we already have a list of interfaces, and we're running as
213 a DHCP server, the interfaces were requested. */
214 if (interfaces
&& (state
== DISCOVER_SERVER
||
215 state
== DISCOVER_RELAY
||
216 state
== DISCOVER_REQUESTED
))
218 else if (state
== DISCOVER_UNCONFIGURED
)
219 ir
= INTERFACE_REQUESTED
| INTERFACE_AUTOMATIC
;
221 ir
= INTERFACE_REQUESTED
;
223 /* Cycle through the list of interfaces looking for IP addresses. */
224 for (i
= 0; i
< ic
.ifc_len
;) {
225 struct ifreq
*ifp
= (struct ifreq
*)((caddr_t
)ic
.ifc_req
+ i
);
227 if (ifp
-> ifr_addr
.sa_len
> sizeof (struct sockaddr
))
228 i
+= (sizeof ifp
-> ifr_name
) + ifp
-> ifr_addr
.sa_len
;
233 #ifdef ALIAS_NAMES_PERMUTED
234 if ((s
= strrchr (ifp
-> ifr_name
, ':'))) {
239 #ifdef SKIP_DUMMY_INTERFACES
240 if (!strncmp (ifp
-> ifr_name
, "dummy", 5))
245 /* See if this is the sort of interface we want to
247 strcpy (ifr
.ifr_name
, ifp
-> ifr_name
);
248 #ifdef SOCKET_IS_NOT_A_FILE
249 if (IoctlSocket (sock
, SIOCGIFFLAGS
, (char *)&ifr
) < 0)
251 if (ioctl (sock
, SIOCGIFFLAGS
, &ifr
) < 0)
253 log_fatal ("Can't get interface flags for %s: %m",
256 /* See if we've seen an interface that matches this one. */
257 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
)
258 if (!strcmp (tmp
-> name
, ifp
-> ifr_name
))
261 /* Skip non broadcast interfaces (plus loopback and
262 point-to-point in case an OS incorrectly marks them
263 as broadcast). Also skip down interfaces unless we're
264 trying to get a list of configurable interfaces. */
265 if (((!(ifr
.ifr_flags
& IFF_BROADCAST
) ||
266 ifr
.ifr_flags
& IFF_LOOPBACK
||
267 ifr
.ifr_flags
& IFF_POINTOPOINT
) && !tmp
) ||
268 (!(ifr
.ifr_flags
& IFF_UP
) &&
269 state
!= DISCOVER_UNCONFIGURED
))
272 /* If there isn't already an interface by this name,
275 tmp
= (struct interface_info
*)0;
276 status
= interface_allocate (&tmp
, MDL
);
277 if (status
!= ISC_R_SUCCESS
)
278 log_fatal ("Error allocating interface %s: %s",
280 isc_result_totext (status
));
281 strcpy (tmp
-> name
, ifp
-> ifr_name
);
282 interface_snorf (tmp
, ir
);
283 interface_dereference (&tmp
, MDL
);
284 tmp
= interfaces
; /* XXX */
287 if (dhcp_interface_discovery_hook
)
288 (*dhcp_interface_discovery_hook
) (tmp
);
290 /* If we have the capability, extract link information
291 and record it in a linked list. */
293 if (ifp
-> ifr_addr
.sa_family
== AF_LINK
) {
294 struct sockaddr_dl
*foo
= ((struct sockaddr_dl
*)
296 #if defined (HAVE_SIN_LEN)
297 tmp
-> hw_address
.hlen
= foo
-> sdl_alen
;
299 tmp
-> hw_address
.hlen
= 6; /* XXX!!! */
301 tmp
-> hw_address
.hbuf
[0] = HTYPE_ETHER
; /* XXX */
302 memcpy (&tmp
-> hw_address
.hbuf
[1],
303 LLADDR (foo
), tmp
-> hw_address
.hlen
);
304 tmp
-> hw_address
.hlen
++; /* for type. */
308 if (ifp
-> ifr_addr
.sa_family
== AF_INET
) {
311 /* Get a pointer to the address... */
312 memcpy (&foo
, &ifp
-> ifr_addr
,
313 sizeof ifp
-> ifr_addr
);
315 /* We don't want the loopback interface. */
316 if (foo
.sin_addr
.s_addr
== htonl (INADDR_LOOPBACK
) &&
317 ((tmp
-> flags
& INTERFACE_AUTOMATIC
) &&
318 state
== DISCOVER_SERVER
))
322 /* If this is the first real IP address we've
323 found, keep a pointer to ifreq structure in
324 which we found it. */
327 unsigned len
= ((sizeof ifp
-> ifr_name
) +
328 ifp
-> ifr_addr
.sa_len
);
330 unsigned len
= sizeof *ifp
;
332 tif
= (struct ifreq
*)dmalloc (len
, MDL
);
334 log_fatal ("no space for ifp.");
335 memcpy (tif
, ifp
, len
);
337 tmp
-> primary_address
= foo
.sin_addr
;
340 /* Grab the address... */
342 memcpy (addr
.iabuf
, &foo
.sin_addr
.s_addr
,
344 if (dhcp_interface_setup_hook
)
345 (*dhcp_interface_setup_hook
) (tmp
, &addr
);
349 /* If we allocated a buffer, free it. */
350 if (ic
.ifc_ifcu
.ifcu_buf
!= buf
)
351 dfree (ic
.ifc_ifcu
.ifcu_buf
, MDL
);
353 #if defined (LINUX_SLASHPROC_DISCOVERY)
354 /* On Linux, interfaces that don't have IP addresses don't
355 show up in the SIOCGIFCONF syscall. This only matters for
356 the DHCP client, of course - the relay agent and server
357 should only care about interfaces that are configured with
360 The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
361 that, when read, prints a human readable network status. We
362 extract the names of the network devices by skipping the first
363 two lines (which are header) and then parsing off everything
364 up to the colon in each subsequent line - these lines start
365 with the interface name, then a colon, then a bunch of
368 if (state
== DISCOVER_UNCONFIGURED
) {
373 proc_dev
= fopen (PROCDEV_DEVICE
, "r");
375 log_fatal ("%s: %m", PROCDEV_DEVICE
);
377 while (fgets (buffer
, sizeof buffer
, proc_dev
)) {
381 /* Skip the first two blocks, which are header
388 sep
= strrchr (buffer
, ':');
394 /* See if we've seen an interface that matches
396 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
)
397 if (!strcmp (tmp
-> name
, name
))
400 /* If we found one, nothing more to do.. */
404 strncpy (ifr
.ifr_name
, name
, IFNAMSIZ
);
406 /* Skip non broadcast interfaces (plus loopback and
407 * point-to-point in case an OS incorrectly marks them
410 #ifdef SOCKET_IS_NOT_A_FILE
411 if ((IoctlSocket (sock
, SIOCGIFFLAGS
, &ifr
) < 0) ||
413 if ((ioctl (sock
, SIOCGIFFLAGS
, &ifr
) < 0) ||
415 (!(ifr
.ifr_flags
& IFF_BROADCAST
)) ||
416 (ifr
.ifr_flags
& IFF_LOOPBACK
) ||
417 (ifr
.ifr_flags
& IFF_POINTOPOINT
))
420 /* Otherwise, allocate one. */
421 tmp
= (struct interface_info
*)0;
422 status
= interface_allocate (&tmp
, MDL
);
423 if (status
!= ISC_R_SUCCESS
)
424 log_fatal ("Can't allocate interface %s: %s",
425 name
, isc_result_totext (status
));
427 strncpy (tmp
-> name
, name
, IFNAMSIZ
);
429 interface_reference (&tmp
-> next
,
431 interface_dereference (&interfaces
, MDL
);
433 interface_reference (&interfaces
, tmp
, MDL
);
434 interface_dereference (&tmp
, MDL
);
437 if (dhcp_interface_discovery_hook
)
438 (*dhcp_interface_discovery_hook
) (tmp
);
445 /* Now cycle through all the interfaces we found, looking for
446 hardware addresses. */
447 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
448 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
) {
454 /* Make up an ifreq structure. */
455 tif
= (struct ifreq
*)dmalloc (sizeof (struct ifreq
),
458 log_fatal ("no space to remember ifp.");
459 memset (tif
, 0, sizeof (struct ifreq
));
460 strcpy (tif
-> ifr_name
, tmp
-> name
);
464 /* Read the hardware address from this interface. */
466 #ifdef SOCKET_IS_NOT_A_FILE
467 if (IoctlSocket (sock
, SIOCGIFHWADDR
, &ifr
) <0)
469 if (ioctl (sock
, SIOCGIFHWADDR
, &ifr
) < 0)
473 sa
= *(struct sockaddr
*)&ifr
.ifr_hwaddr
;
475 switch (sa
.sa_family
) {
476 #ifdef HAVE_ARPHRD_TUNNEL
478 /* ignore tunnel interfaces. */
480 #ifdef HAVE_ARPHRD_ROSE
483 #ifdef HAVE_ARPHRD_LOOPBACK
484 case ARPHRD_LOOPBACK
:
485 /* ignore loopback interface */
490 tmp
-> hw_address
.hlen
= 7;
491 tmp
-> hw_address
.hbuf
[0] = ARPHRD_ETHER
;
492 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
495 #ifndef HAVE_ARPHRD_IEEE802
496 # define ARPHRD_IEEE802 HTYPE_IEEE802
498 #if defined (HAVE_ARPHRD_IEEE802_TR)
499 case ARPHRD_IEEE802_TR
:
502 tmp
-> hw_address
.hlen
= 7;
503 tmp
-> hw_address
.hbuf
[0] = ARPHRD_IEEE802
;
504 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
507 #ifndef HAVE_ARPHRD_FDDI
508 # define ARPHRD_FDDI HTYPE_FDDI
511 tmp
-> hw_address
.hlen
= 17;
512 tmp
-> hw_address
.hbuf
[0] = HTYPE_FDDI
; /* XXX */
513 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 16);
516 #ifdef HAVE_ARPHRD_METRICOM
517 case ARPHRD_METRICOM
:
518 tmp
-> hw_address
.hlen
= 7;
519 tmp
-> hw_address
.hbuf
[0] = ARPHRD_METRICOM
;
520 memcpy (&tmp
-> hw_address
.hbuf
[0], sa
.sa_data
, 6);
524 #ifdef HAVE_ARPHRD_AX25
526 tmp
-> hw_address
.hlen
= 7;
527 tmp
-> hw_address
.hbuf
[0] = ARPHRD_AX25
;
528 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
532 #ifdef HAVE_ARPHRD_NETROM
534 tmp
-> hw_address
.hlen
= 7;
535 tmp
-> hw_address
.hbuf
[0] = ARPHRD_NETROM
;
536 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
541 log_error ("%s: unknown hardware address type %d",
542 ifr
.ifr_name
, sa
.sa_family
);
546 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
548 /* If we're just trying to get a list of interfaces that we might
549 be able to configure, we can quit now. */
550 if (state
== DISCOVER_UNCONFIGURED
) {
551 #ifdef SOCKET_IS_NOT_A_FILE
559 /* Weed out the interfaces that did not have IP addresses. */
560 tmp
= last
= next
= (struct interface_info
*)0;
562 interface_reference (&tmp
, interfaces
, MDL
);
565 interface_dereference (&next
, MDL
);
567 interface_reference (&next
, tmp
-> next
, MDL
);
568 /* skip interfaces that are running already */
569 if (tmp
-> flags
& INTERFACE_RUNNING
) {
570 interface_dereference(&tmp
, MDL
);
572 interface_reference(&tmp
, next
, MDL
);
575 if ((tmp
-> flags
& INTERFACE_AUTOMATIC
) &&
576 state
== DISCOVER_REQUESTED
)
577 tmp
-> flags
&= ~(INTERFACE_AUTOMATIC
|
578 INTERFACE_REQUESTED
);
579 if (!tmp
-> ifp
|| !(tmp
-> flags
& INTERFACE_REQUESTED
)) {
580 if ((tmp
-> flags
& INTERFACE_REQUESTED
) != ir
)
581 log_fatal ("%s: not found", tmp
-> name
);
584 interface_dereference (&interfaces
,
587 interface_reference (&interfaces
, next
, MDL
);
589 interface_dereference (&last
-> next
, MDL
);
591 interface_reference (&last
-> next
,
595 interface_dereference (&tmp
-> next
, MDL
);
597 /* Remember the interface in case we need to know
599 if (dummy_interfaces
) {
600 interface_reference (&tmp
-> next
,
601 dummy_interfaces
, MDL
);
602 interface_dereference (&dummy_interfaces
, MDL
);
604 interface_reference (&dummy_interfaces
, tmp
, MDL
);
605 interface_dereference (&tmp
, MDL
);
607 interface_reference (&tmp
, next
, MDL
);
612 memcpy (&foo
, &tmp
-> ifp
-> ifr_addr
,
613 sizeof tmp
-> ifp
-> ifr_addr
);
615 /* We must have a subnet declaration for each interface. */
616 if (!tmp
-> shared_network
&& (state
== DISCOVER_SERVER
)) {
617 log_error ("%s", "");
618 log_error ("No subnet declaration for %s (%s).",
619 tmp
-> name
, inet_ntoa (foo
.sin_addr
));
620 if (supports_multiple_interfaces (tmp
)) {
621 log_error ("** Ignoring requests on %s. %s",
622 tmp
-> name
, "If this is not what");
623 log_error (" you want, please write %s",
624 "a subnet declaration");
625 log_error (" in your dhcpd.conf file %s",
626 "for the network segment");
627 log_error (" to %s %s %s",
629 tmp
-> name
, "is attached. **");
630 log_error ("%s", "");
633 log_error ("You must write a subnet %s",
634 " declaration for this");
635 log_error ("subnet. You cannot prevent %s",
637 log_error ("from listening on this subnet %s",
639 log_fatal ("operating system does not %s.",
640 "support this capability");
644 /* Find subnets that don't have valid interface
646 for (subnet
= (tmp
-> shared_network
647 ? tmp
-> shared_network
-> subnets
648 : (struct subnet
*)0);
649 subnet
; subnet
= subnet
-> next_sibling
) {
650 if (!subnet
-> interface_address
.len
) {
651 /* Set the interface address for this subnet
652 to the first address we found. */
653 subnet
-> interface_address
.len
= 4;
654 memcpy (subnet
-> interface_address
.iabuf
,
655 &foo
.sin_addr
.s_addr
, 4);
659 /* Flag the index as not having been set, so that the
660 interface registerer can set it or not as it chooses. */
663 /* Register the interface... */
664 if_register_receive (tmp
);
665 if_register_send (tmp
);
667 interface_stash (tmp
);
669 #if defined (HAVE_SETFD)
670 if (fcntl (tmp
-> rfdesc
, F_SETFD
, 1) < 0)
671 log_error ("Can't set close-on-exec on %s: %m",
673 if (tmp
-> rfdesc
!= tmp
-> wfdesc
) {
674 if (fcntl (tmp
-> wfdesc
, F_SETFD
, 1) < 0)
675 log_error ("Can't set close-on-exec on %s: %m",
680 interface_dereference (&tmp
, MDL
);
682 interface_reference (&tmp
, next
, MDL
);
685 /* Now register all the remaining interfaces as protocols. */
686 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
) {
687 /* not if it's been registered before */
688 if (tmp
-> flags
& INTERFACE_RUNNING
)
690 if (tmp
-> rfdesc
== -1)
692 status
= omapi_register_io_object ((omapi_object_t
*)tmp
,
695 if (status
!= ISC_R_SUCCESS
)
696 log_fatal ("Can't register I/O handle for %s: %s",
697 tmp
-> name
, isc_result_totext (status
));
699 #ifdef SOCKET_IS_NOT_A_FILE
704 if (state
== DISCOVER_SERVER
&& wifcount
== 0) {
706 log_fatal ("Not configured to listen on any interfaces!");
709 if (!setup_fallback
) {
711 maybe_setup_fallback ();
714 #if defined (HAVE_SETFD)
715 if (fallback_interface
) {
716 if (fcntl (fallback_interface
-> rfdesc
, F_SETFD
, 1) < 0)
717 log_error ("Can't set close-on-exec on fallback: %m");
718 if (fallback_interface
-> rfdesc
!= fallback_interface
-> wfdesc
) {
719 if (fcntl (fallback_interface
-> wfdesc
, F_SETFD
, 1) < 0)
720 log_error ("Can't set close-on-exec on fallback: %m");
726 int if_readsocket (h
)
729 struct interface_info
*ip
;
731 if (h
-> type
!= dhcp_type_interface
)
733 ip
= (struct interface_info
*)h
;
737 int setup_fallback (struct interface_info
**fp
, const char *file
, int line
)
741 status
= interface_allocate (&fallback_interface
, file
, line
);
742 if (status
!= ISC_R_SUCCESS
)
743 log_fatal ("Error allocating fallback interface: %s",
744 isc_result_totext (status
));
745 strcpy (fallback_interface
-> name
, "fallback");
746 if (dhcp_interface_setup_hook
)
747 (*dhcp_interface_setup_hook
) (fallback_interface
,
749 status
= interface_reference (fp
, fallback_interface
, file
, line
);
751 fallback_interface
-> index
= -1;
752 interface_stash (fallback_interface
);
753 return status
== ISC_R_SUCCESS
;
756 void reinitialize_interfaces ()
758 struct interface_info
*ip
;
760 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
761 if_reinitialize_receive (ip
);
762 if_reinitialize_send (ip
);
765 if (fallback_interface
)
766 if_reinitialize_send (fallback_interface
);
768 interfaces_invalidated
= 1;
771 isc_result_t
got_one (h
)
774 struct sockaddr_in from
;
775 struct hardware hfrom
;
779 unsigned char packbuf
[4095]; /* Packet input buffer.
780 Must be as large as largest
782 struct dhcp_packet packet
;
784 struct interface_info
*ip
;
786 if (h
-> type
!= dhcp_type_interface
)
787 return ISC_R_INVALIDARG
;
788 ip
= (struct interface_info
*)h
;
792 receive_packet (ip
, u
.packbuf
, sizeof u
, &from
, &hfrom
)) < 0) {
793 log_error ("receive_packet failed on %s: %m", ip
-> name
);
794 return ISC_R_UNEXPECTED
;
797 return ISC_R_UNEXPECTED
;
799 /* If we didn't at least get the fixed portion of the BOOTP
800 packet, drop the packet. We're allowing packets with no
801 sname or filename, because we're aware of at least one
802 client that sends such packets, but this definitely falls
803 into the category of being forgiving. */
804 if (result
< DHCP_FIXED_NON_UDP
- DHCP_SNAME_LEN
- DHCP_FILE_LEN
)
805 return ISC_R_UNEXPECTED
;
807 if (bootp_packet_handler
) {
809 memcpy (ifrom
.iabuf
, &from
.sin_addr
, ifrom
.len
);
811 (*bootp_packet_handler
) (ip
, &u
.packet
, (unsigned)result
,
812 from
.sin_port
, ifrom
, &hfrom
);
815 /* If there is buffered data, read again. This is for, e.g.,
816 bpf, which may return two packets at once. */
817 if (ip
-> rbuf_offset
!= ip
-> rbuf_len
)
819 return ISC_R_SUCCESS
;
822 isc_result_t
dhcp_interface_set_value (omapi_object_t
*h
,
824 omapi_data_string_t
*name
,
825 omapi_typed_data_t
*value
)
827 struct interface_info
*interface
;
831 if (h
-> type
!= dhcp_type_interface
)
832 return ISC_R_INVALIDARG
;
833 interface
= (struct interface_info
*)h
;
835 if (!omapi_ds_strcmp (name
, "name")) {
836 if ((value
-> type
== omapi_datatype_data
||
837 value
-> type
== omapi_datatype_string
) &&
838 value
-> u
.buffer
.len
< sizeof interface
-> name
) {
839 memcpy (interface
-> name
,
840 value
-> u
.buffer
.value
,
841 value
-> u
.buffer
.len
);
842 interface
-> name
[value
-> u
.buffer
.len
] = 0;
844 return ISC_R_INVALIDARG
;
845 return ISC_R_SUCCESS
;
848 /* Try to find some inner object that can take the value. */
849 if (h
-> inner
&& h
-> inner
-> type
-> set_value
) {
850 status
= ((*(h
-> inner
-> type
-> set_value
))
851 (h
-> inner
, id
, name
, value
));
852 if (status
== ISC_R_SUCCESS
|| status
== ISC_R_UNCHANGED
)
856 return ISC_R_NOTFOUND
;
860 isc_result_t
dhcp_interface_get_value (omapi_object_t
*h
,
862 omapi_data_string_t
*name
,
863 omapi_value_t
**value
)
865 return ISC_R_NOTIMPLEMENTED
;
868 isc_result_t
dhcp_interface_destroy (omapi_object_t
*h
,
869 const char *file
, int line
)
871 struct interface_info
*interface
;
872 // isc_result_t status;
874 if (h
-> type
!= dhcp_type_interface
)
875 return ISC_R_INVALIDARG
;
876 interface
= (struct interface_info
*)h
;
878 if (interface
-> ifp
) {
879 dfree (interface
-> ifp
, file
, line
);
880 interface
-> ifp
= 0;
882 if (interface
-> next
)
883 interface_dereference (&interface
-> next
, file
, line
);
884 if (interface
-> rbuf
) {
885 dfree (interface
-> rbuf
, file
, line
);
886 interface
-> rbuf
= (unsigned char *)0;
888 if (interface
-> client
)
889 interface
-> client
= (struct client_state
*)0;
891 if (interface
-> shared_network
)
892 omapi_object_dereference ((omapi_object_t
**)
893 &interface
-> shared_network
, MDL
);
895 return ISC_R_SUCCESS
;
898 isc_result_t
dhcp_interface_signal_handler (omapi_object_t
*h
,
899 const char *name
, va_list ap
)
901 struct interface_info
*ip
, *interface
;
902 // struct client_config *config;
903 // struct client_state *client;
906 if (h
-> type
!= dhcp_type_interface
)
907 return ISC_R_INVALIDARG
;
908 interface
= (struct interface_info
*)h
;
910 /* If it's an update signal, see if the interface is dead right
911 now, or isn't known at all, and if that's the case, revive it. */
912 if (!strcmp (name
, "update")) {
913 for (ip
= dummy_interfaces
; ip
; ip
= ip
-> next
)
916 if (ip
&& dhcp_interface_startup_hook
)
917 return (*dhcp_interface_startup_hook
) (ip
);
919 for (ip
= interfaces
; ip
; ip
= ip
-> next
)
922 if (!ip
&& dhcp_interface_startup_hook
)
923 return (*dhcp_interface_startup_hook
) (ip
);
926 /* Try to find some inner object that can take the value. */
927 if (h
-> inner
&& h
-> inner
-> type
-> get_value
) {
928 status
= ((*(h
-> inner
-> type
-> signal_handler
))
929 (h
-> inner
, name
, ap
));
930 if (status
== ISC_R_SUCCESS
)
933 return ISC_R_NOTFOUND
;
936 isc_result_t
dhcp_interface_stuff_values (omapi_object_t
*c
,
940 struct interface_info
*interface
;
943 if (h
-> type
!= dhcp_type_interface
)
944 return ISC_R_INVALIDARG
;
945 interface
= (struct interface_info
*)h
;
947 /* Write out all the values. */
949 status
= omapi_connection_put_name (c
, "state");
950 if (status
!= ISC_R_SUCCESS
)
952 if (interface
-> flags
&& INTERFACE_REQUESTED
)
953 status
= omapi_connection_put_string (c
, "up");
955 status
= omapi_connection_put_string (c
, "down");
956 if (status
!= ISC_R_SUCCESS
)
959 /* Write out the inner object, if any. */
960 if (h
-> inner
&& h
-> inner
-> type
-> stuff_values
) {
961 status
= ((*(h
-> inner
-> type
-> stuff_values
))
962 (c
, id
, h
-> inner
));
963 if (status
== ISC_R_SUCCESS
)
967 return ISC_R_SUCCESS
;
970 isc_result_t
dhcp_interface_lookup (omapi_object_t
**ip
,
974 omapi_value_t
*tv
= (omapi_value_t
*)0;
976 struct interface_info
*interface
;
981 /* First see if we were sent a handle. */
982 status
= omapi_get_value_str (ref
, id
, "handle", &tv
);
983 if (status
== ISC_R_SUCCESS
) {
984 status
= omapi_handle_td_lookup (ip
, tv
-> value
);
986 omapi_value_dereference (&tv
, MDL
);
987 if (status
!= ISC_R_SUCCESS
)
990 /* Don't return the object if the type is wrong. */
991 if ((*ip
) -> type
!= dhcp_type_interface
) {
992 omapi_object_dereference (ip
, MDL
);
993 return ISC_R_INVALIDARG
;
997 /* Now look for an interface name. */
998 status
= omapi_get_value_str (ref
, id
, "name", &tv
);
999 if (status
== ISC_R_SUCCESS
) {
1002 for (interface
= interfaces
; interface
;
1003 interface
= interface
-> next
) {
1004 s
= memchr (interface
-> name
, 0, IFNAMSIZ
);
1006 len
= s
- &interface
-> name
[0];
1009 if ((tv
-> value
-> u
.buffer
.len
== len
&&
1010 !memcmp (interface
-> name
,
1011 (char *)tv
-> value
-> u
.buffer
.value
,
1016 for (interface
= dummy_interfaces
;
1017 interface
; interface
= interface
-> next
) {
1018 s
= memchr (interface
-> name
, 0, IFNAMSIZ
);
1020 len
= s
- &interface
-> name
[0];
1023 if ((tv
-> value
-> u
.buffer
.len
== len
&&
1024 !memcmp (interface
-> name
,
1026 tv
-> value
-> u
.buffer
.value
,
1032 omapi_value_dereference (&tv
, MDL
);
1033 if (*ip
&& *ip
!= (omapi_object_t
*)interface
) {
1034 omapi_object_dereference (ip
, MDL
);
1035 return ISC_R_KEYCONFLICT
;
1036 } else if (!interface
) {
1038 omapi_object_dereference (ip
, MDL
);
1039 return ISC_R_NOTFOUND
;
1041 omapi_object_reference (ip
,
1042 (omapi_object_t
*)interface
,
1046 /* If we get to here without finding an interface, no valid key was
1049 return ISC_R_NOKEYS
;
1050 return ISC_R_SUCCESS
;
1053 /* actually just go discover the interface */
1054 isc_result_t
dhcp_interface_create (omapi_object_t
**lp
,
1057 struct interface_info
*hp
;
1058 isc_result_t status
;
1060 hp
= (struct interface_info
*)0;
1061 status
= interface_allocate (&hp
, MDL
);
1062 if (status
!= ISC_R_SUCCESS
)
1064 hp
-> flags
= INTERFACE_REQUESTED
;
1065 status
= interface_reference ((struct interface_info
**)lp
, hp
, MDL
);
1066 interface_dereference (&hp
, MDL
);
1070 isc_result_t
dhcp_interface_remove (omapi_object_t
*lp
,
1073 struct interface_info
*interface
, *ip
, *last
;
1075 interface
= (struct interface_info
*)lp
;
1077 /* remove from interfaces */
1079 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
1080 if (ip
== interface
) {
1082 interface_dereference (&last
-> next
, MDL
);
1084 interface_reference (&last
-> next
,
1087 interface_dereference (&interfaces
, MDL
);
1089 interface_reference (&interfaces
,
1093 interface_dereference (&ip
-> next
, MDL
);
1099 return ISC_R_NOTFOUND
;
1101 /* add the interface to the dummy_interface list */
1102 if (dummy_interfaces
) {
1103 interface_reference (&interface
-> next
,
1104 dummy_interfaces
, MDL
);
1105 interface_dereference (&dummy_interfaces
, MDL
);
1107 interface_reference (&dummy_interfaces
, interface
, MDL
);
1109 /* do a DHCPRELEASE */
1110 if (dhcp_interface_shutdown_hook
)
1111 (*dhcp_interface_shutdown_hook
) (interface
);
1113 /* remove the io object */
1114 omapi_unregister_io_object ((omapi_object_t
*)interface
);
1116 if_deregister_send (interface
);
1117 if_deregister_receive (interface
);
1119 return ISC_R_SUCCESS
;
1122 void interface_stash (struct interface_info
*tptr
)
1124 struct interface_info
**vec
;
1127 /* If the registerer didn't assign an index, assign one now. */
1128 if (tptr
-> index
== -1) {
1129 tptr
-> index
= interface_count
++;
1130 while (tptr
-> index
< interface_max
&&
1131 interface_vector
[tptr
-> index
])
1132 tptr
-> index
= interface_count
++;
1135 if (interface_max
<= tptr
-> index
) {
1136 delta
= tptr
-> index
- interface_max
+ 10;
1137 vec
= dmalloc ((interface_max
+ delta
) *
1138 sizeof (struct interface_info
*), MDL
);
1141 memset (&vec
[interface_max
], 0,
1142 (sizeof (struct interface_info
*)) * delta
);
1143 interface_max
+= delta
;
1144 if (interface_vector
) {
1145 memcpy (vec
, interface_vector
,
1147 sizeof (struct interface_info
*)));
1148 dfree (interface_vector
, MDL
);
1150 interface_vector
= vec
;
1152 interface_reference (&interface_vector
[tptr
-> index
], tptr
, MDL
);
1153 if (tptr
-> index
>= interface_count
)
1154 interface_count
= tptr
-> index
+ 1;
1155 #if defined (TRACING)
1156 trace_interface_register (interface_trace
, tptr
);
1160 void interface_snorf (struct interface_info
*tmp
, int ir
)
1162 tmp
-> circuit_id
= (u_int8_t
*)tmp
-> name
;
1163 tmp
-> circuit_id_len
= strlen (tmp
-> name
);
1164 tmp
-> remote_id
= 0;
1165 tmp
-> remote_id_len
= 0;
1168 interface_reference (&tmp
-> next
,
1170 interface_dereference (&interfaces
, MDL
);
1172 interface_reference (&interfaces
, tmp
, MDL
);