3 Network input dispatcher... */
6 * Copyright (c) 2004 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.42.2.15 2004/06/10 17:59:16 dhankins Exp $ Copyright (c) 2004 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 /* Otherwise, allocate one. */
396 tmp
= (struct interface_info
*)0;
397 status
= interface_allocate (&tmp
, MDL
);
398 if (status
!= ISC_R_SUCCESS
)
399 log_fatal ("Can't allocate interface %s: %s",
400 name
, isc_result_totext (status
));
402 strncpy (tmp
-> name
, name
, IFNAMSIZ
);
404 interface_reference (&tmp
-> next
,
406 interface_dereference (&interfaces
, MDL
);
408 interface_reference (&interfaces
, tmp
, MDL
);
409 interface_dereference (&tmp
, MDL
);
412 if (dhcp_interface_discovery_hook
)
413 (*dhcp_interface_discovery_hook
) (tmp
);
420 /* Now cycle through all the interfaces we found, looking for
421 hardware addresses. */
422 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
423 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
) {
429 /* Make up an ifreq structure. */
430 tif
= (struct ifreq
*)dmalloc (sizeof (struct ifreq
),
433 log_fatal ("no space to remember ifp.");
434 memset (tif
, 0, sizeof (struct ifreq
));
435 strcpy (tif
-> ifr_name
, tmp
-> name
);
439 /* Read the hardware address from this interface. */
441 if (ioctl (sock
, SIOCGIFHWADDR
, &ifr
) < 0)
444 sa
= *(struct sockaddr
*)&ifr
.ifr_hwaddr
;
446 switch (sa
.sa_family
) {
447 #ifdef HAVE_ARPHRD_TUNNEL
449 /* ignore tunnel interfaces. */
451 #ifdef HAVE_ARPHRD_ROSE
454 #ifdef HAVE_ARPHRD_LOOPBACK
455 case ARPHRD_LOOPBACK
:
456 /* ignore loopback interface */
461 tmp
-> hw_address
.hlen
= 7;
462 tmp
-> hw_address
.hbuf
[0] = ARPHRD_ETHER
;
463 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
466 #ifndef HAVE_ARPHRD_IEEE802
467 # define ARPHRD_IEEE802 HTYPE_IEEE802
469 #if defined (HAVE_ARPHRD_IEEE802_TR)
470 case ARPHRD_IEEE802_TR
:
473 tmp
-> hw_address
.hlen
= 7;
474 tmp
-> hw_address
.hbuf
[0] = ARPHRD_IEEE802
;
475 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
478 #ifndef HAVE_ARPHRD_FDDI
479 # define ARPHRD_FDDI HTYPE_FDDI
482 tmp
-> hw_address
.hlen
= 17;
483 tmp
-> hw_address
.hbuf
[0] = HTYPE_FDDI
; /* XXX */
484 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 16);
487 #ifdef HAVE_ARPHRD_METRICOM
488 case ARPHRD_METRICOM
:
489 tmp
-> hw_address
.hlen
= 7;
490 tmp
-> hw_address
.hbuf
[0] = ARPHRD_METRICOM
;
491 memcpy (&tmp
-> hw_address
.hbuf
[0], sa
.sa_data
, 6);
495 #ifdef HAVE_ARPHRD_AX25
497 tmp
-> hw_address
.hlen
= 7;
498 tmp
-> hw_address
.hbuf
[0] = ARPHRD_AX25
;
499 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
503 #ifdef HAVE_ARPHRD_NETROM
505 tmp
-> hw_address
.hlen
= 7;
506 tmp
-> hw_address
.hbuf
[0] = ARPHRD_NETROM
;
507 memcpy (&tmp
-> hw_address
.hbuf
[1], sa
.sa_data
, 6);
512 log_error ("%s: unknown hardware address type %d",
513 ifr
.ifr_name
, sa
.sa_family
);
517 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
519 /* If we're just trying to get a list of interfaces that we might
520 be able to configure, we can quit now. */
521 if (state
== DISCOVER_UNCONFIGURED
) {
526 /* Weed out the interfaces that did not have IP addresses. */
527 tmp
= last
= next
= (struct interface_info
*)0;
529 interface_reference (&tmp
, interfaces
, MDL
);
532 interface_dereference (&next
, MDL
);
534 interface_reference (&next
, tmp
-> next
, MDL
);
535 /* skip interfaces that are running already */
536 if (tmp
-> flags
& INTERFACE_RUNNING
) {
537 interface_dereference(&tmp
, MDL
);
539 interface_reference(&tmp
, next
, MDL
);
542 if ((tmp
-> flags
& INTERFACE_AUTOMATIC
) &&
543 state
== DISCOVER_REQUESTED
)
544 tmp
-> flags
&= ~(INTERFACE_AUTOMATIC
|
545 INTERFACE_REQUESTED
);
546 if (!tmp
-> ifp
|| !(tmp
-> flags
& INTERFACE_REQUESTED
)) {
547 if ((tmp
-> flags
& INTERFACE_REQUESTED
) != ir
)
548 log_fatal ("%s: not found", tmp
-> name
);
551 interface_dereference (&interfaces
,
554 interface_reference (&interfaces
, next
, MDL
);
556 interface_dereference (&last
-> next
, MDL
);
558 interface_reference (&last
-> next
,
562 interface_dereference (&tmp
-> next
, MDL
);
564 /* Remember the interface in case we need to know
566 if (dummy_interfaces
) {
567 interface_reference (&tmp
-> next
,
568 dummy_interfaces
, MDL
);
569 interface_dereference (&dummy_interfaces
, MDL
);
571 interface_reference (&dummy_interfaces
, tmp
, MDL
);
572 interface_dereference (&tmp
, MDL
);
574 interface_reference (&tmp
, next
, MDL
);
579 memcpy (&foo
, &tmp
-> ifp
-> ifr_addr
,
580 sizeof tmp
-> ifp
-> ifr_addr
);
582 /* We must have a subnet declaration for each interface. */
583 if (!tmp
-> shared_network
&& (state
== DISCOVER_SERVER
)) {
584 log_error ("%s", "");
585 log_error ("No subnet declaration for %s (%s).",
586 tmp
-> name
, inet_ntoa (foo
.sin_addr
));
587 if (supports_multiple_interfaces (tmp
)) {
588 log_error ("** Ignoring requests on %s. %s",
589 tmp
-> name
, "If this is not what");
590 log_error (" you want, please write %s",
591 "a subnet declaration");
592 log_error (" in your dhcpd.conf file %s",
593 "for the network segment");
594 log_error (" to %s %s %s",
596 tmp
-> name
, "is attached. **");
597 log_error ("%s", "");
600 log_error ("You must write a subnet %s",
601 " declaration for this");
602 log_error ("subnet. You cannot prevent %s",
604 log_error ("from listening on this subnet %s",
606 log_fatal ("operating system does not %s.",
607 "support this capability");
611 /* Find subnets that don't have valid interface
613 for (subnet
= (tmp
-> shared_network
614 ? tmp
-> shared_network
-> subnets
615 : (struct subnet
*)0);
616 subnet
; subnet
= subnet
-> next_sibling
) {
617 if (!subnet
-> interface_address
.len
) {
618 /* Set the interface address for this subnet
619 to the first address we found. */
620 subnet
-> interface_address
.len
= 4;
621 memcpy (subnet
-> interface_address
.iabuf
,
622 &foo
.sin_addr
.s_addr
, 4);
626 /* Flag the index as not having been set, so that the
627 interface registerer can set it or not as it chooses. */
630 /* Register the interface... */
631 if_register_receive (tmp
);
632 if_register_send (tmp
);
634 interface_stash (tmp
);
636 #if defined (HAVE_SETFD)
637 if (fcntl (tmp
-> rfdesc
, F_SETFD
, 1) < 0)
638 log_error ("Can't set close-on-exec on %s: %m",
640 if (tmp
-> rfdesc
!= tmp
-> wfdesc
) {
641 if (fcntl (tmp
-> wfdesc
, F_SETFD
, 1) < 0)
642 log_error ("Can't set close-on-exec on %s: %m",
647 interface_dereference (&tmp
, MDL
);
649 interface_reference (&tmp
, next
, MDL
);
652 /* Now register all the remaining interfaces as protocols. */
653 for (tmp
= interfaces
; tmp
; tmp
= tmp
-> next
) {
654 /* not if it's been registered before */
655 if (tmp
-> flags
& INTERFACE_RUNNING
)
657 if (tmp
-> rfdesc
== -1)
659 status
= omapi_register_io_object ((omapi_object_t
*)tmp
,
662 if (status
!= ISC_R_SUCCESS
)
663 log_fatal ("Can't register I/O handle for %s: %s",
664 tmp
-> name
, isc_result_totext (status
));
669 if (state
== DISCOVER_SERVER
&& wifcount
== 0) {
671 log_fatal ("Not configured to listen on any interfaces!");
674 if (!setup_fallback
) {
676 maybe_setup_fallback ();
679 #if defined (HAVE_SETFD)
680 if (fallback_interface
) {
681 if (fcntl (fallback_interface
-> rfdesc
, F_SETFD
, 1) < 0)
682 log_error ("Can't set close-on-exec on fallback: %m");
683 if (fallback_interface
-> rfdesc
!= fallback_interface
-> wfdesc
) {
684 if (fcntl (fallback_interface
-> wfdesc
, F_SETFD
, 1) < 0)
685 log_error ("Can't set close-on-exec on fallback: %m");
691 int if_readsocket (h
)
694 struct interface_info
*ip
;
696 if (h
-> type
!= dhcp_type_interface
)
698 ip
= (struct interface_info
*)h
;
702 int setup_fallback (struct interface_info
**fp
, const char *file
, int line
)
706 status
= interface_allocate (&fallback_interface
, file
, line
);
707 if (status
!= ISC_R_SUCCESS
)
708 log_fatal ("Error allocating fallback interface: %s",
709 isc_result_totext (status
));
710 strcpy (fallback_interface
-> name
, "fallback");
711 if (dhcp_interface_setup_hook
)
712 (*dhcp_interface_setup_hook
) (fallback_interface
,
714 status
= interface_reference (fp
, fallback_interface
, file
, line
);
716 fallback_interface
-> index
= -1;
717 interface_stash (fallback_interface
);
718 return status
== ISC_R_SUCCESS
;
721 void reinitialize_interfaces ()
723 struct interface_info
*ip
;
725 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
726 if_reinitialize_receive (ip
);
727 if_reinitialize_send (ip
);
730 if (fallback_interface
)
731 if_reinitialize_send (fallback_interface
);
733 interfaces_invalidated
= 1;
736 isc_result_t
got_one (h
)
739 struct sockaddr_in from
;
740 struct hardware hfrom
;
744 unsigned char packbuf
[4095]; /* Packet input buffer.
745 Must be as large as largest
747 struct dhcp_packet packet
;
749 struct interface_info
*ip
;
751 if (h
-> type
!= dhcp_type_interface
)
752 return ISC_R_INVALIDARG
;
753 ip
= (struct interface_info
*)h
;
757 receive_packet (ip
, u
.packbuf
, sizeof u
, &from
, &hfrom
)) < 0) {
758 log_error ("receive_packet failed on %s: %m", ip
-> name
);
759 return ISC_R_UNEXPECTED
;
762 return ISC_R_UNEXPECTED
;
764 /* If we didn't at least get the fixed portion of the BOOTP
765 packet, drop the packet. We're allowing packets with no
766 sname or filename, because we're aware of at least one
767 client that sends such packets, but this definitely falls
768 into the category of being forgiving. */
769 if (result
< DHCP_FIXED_NON_UDP
- DHCP_SNAME_LEN
- DHCP_FILE_LEN
)
770 return ISC_R_UNEXPECTED
;
772 if (bootp_packet_handler
) {
774 memcpy (ifrom
.iabuf
, &from
.sin_addr
, ifrom
.len
);
776 (*bootp_packet_handler
) (ip
, &u
.packet
, (unsigned)result
,
777 from
.sin_port
, ifrom
, &hfrom
);
780 /* If there is buffered data, read again. This is for, e.g.,
781 bpf, which may return two packets at once. */
782 if (ip
-> rbuf_offset
!= ip
-> rbuf_len
)
784 return ISC_R_SUCCESS
;
787 isc_result_t
dhcp_interface_set_value (omapi_object_t
*h
,
789 omapi_data_string_t
*name
,
790 omapi_typed_data_t
*value
)
792 struct interface_info
*interface
;
796 if (h
-> type
!= dhcp_type_interface
)
797 return ISC_R_INVALIDARG
;
798 interface
= (struct interface_info
*)h
;
800 if (!omapi_ds_strcmp (name
, "name")) {
801 if ((value
-> type
== omapi_datatype_data
||
802 value
-> type
== omapi_datatype_string
) &&
803 value
-> u
.buffer
.len
< sizeof interface
-> name
) {
804 memcpy (interface
-> name
,
805 value
-> u
.buffer
.value
,
806 value
-> u
.buffer
.len
);
807 interface
-> name
[value
-> u
.buffer
.len
] = 0;
809 return ISC_R_INVALIDARG
;
810 return ISC_R_SUCCESS
;
813 /* Try to find some inner object that can take the value. */
814 if (h
-> inner
&& h
-> inner
-> type
-> set_value
) {
815 status
= ((*(h
-> inner
-> type
-> set_value
))
816 (h
-> inner
, id
, name
, value
));
817 if (status
== ISC_R_SUCCESS
|| status
== ISC_R_UNCHANGED
)
821 return ISC_R_NOTFOUND
;
825 isc_result_t
dhcp_interface_get_value (omapi_object_t
*h
,
827 omapi_data_string_t
*name
,
828 omapi_value_t
**value
)
830 return ISC_R_NOTIMPLEMENTED
;
833 isc_result_t
dhcp_interface_destroy (omapi_object_t
*h
,
834 const char *file
, int line
)
836 struct interface_info
*interface
;
839 if (h
-> type
!= dhcp_type_interface
)
840 return ISC_R_INVALIDARG
;
841 interface
= (struct interface_info
*)h
;
843 if (interface
-> ifp
) {
844 dfree (interface
-> ifp
, file
, line
);
845 interface
-> ifp
= 0;
847 if (interface
-> next
)
848 interface_dereference (&interface
-> next
, file
, line
);
849 if (interface
-> rbuf
) {
850 dfree (interface
-> rbuf
, file
, line
);
851 interface
-> rbuf
= (unsigned char *)0;
853 if (interface
-> client
)
854 interface
-> client
= (struct client_state
*)0;
856 if (interface
-> shared_network
)
857 omapi_object_dereference ((omapi_object_t
**)
858 &interface
-> shared_network
, MDL
);
860 return ISC_R_SUCCESS
;
863 isc_result_t
dhcp_interface_signal_handler (omapi_object_t
*h
,
864 const char *name
, va_list ap
)
866 struct interface_info
*ip
, *interface
;
867 struct client_config
*config
;
868 struct client_state
*client
;
871 if (h
-> type
!= dhcp_type_interface
)
872 return ISC_R_INVALIDARG
;
873 interface
= (struct interface_info
*)h
;
875 /* If it's an update signal, see if the interface is dead right
876 now, or isn't known at all, and if that's the case, revive it. */
877 if (!strcmp (name
, "update")) {
878 for (ip
= dummy_interfaces
; ip
; ip
= ip
-> next
)
881 if (ip
&& dhcp_interface_startup_hook
)
882 return (*dhcp_interface_startup_hook
) (ip
);
884 for (ip
= interfaces
; ip
; ip
= ip
-> next
)
887 if (!ip
&& dhcp_interface_startup_hook
)
888 return (*dhcp_interface_startup_hook
) (ip
);
891 /* Try to find some inner object that can take the value. */
892 if (h
-> inner
&& h
-> inner
-> type
-> get_value
) {
893 status
= ((*(h
-> inner
-> type
-> signal_handler
))
894 (h
-> inner
, name
, ap
));
895 if (status
== ISC_R_SUCCESS
)
898 return ISC_R_NOTFOUND
;
901 isc_result_t
dhcp_interface_stuff_values (omapi_object_t
*c
,
905 struct interface_info
*interface
;
908 if (h
-> type
!= dhcp_type_interface
)
909 return ISC_R_INVALIDARG
;
910 interface
= (struct interface_info
*)h
;
912 /* Write out all the values. */
914 status
= omapi_connection_put_name (c
, "state");
915 if (status
!= ISC_R_SUCCESS
)
917 if (interface
-> flags
&& INTERFACE_REQUESTED
)
918 status
= omapi_connection_put_string (c
, "up");
920 status
= omapi_connection_put_string (c
, "down");
921 if (status
!= ISC_R_SUCCESS
)
924 /* Write out the inner object, if any. */
925 if (h
-> inner
&& h
-> inner
-> type
-> stuff_values
) {
926 status
= ((*(h
-> inner
-> type
-> stuff_values
))
927 (c
, id
, h
-> inner
));
928 if (status
== ISC_R_SUCCESS
)
932 return ISC_R_SUCCESS
;
935 isc_result_t
dhcp_interface_lookup (omapi_object_t
**ip
,
939 omapi_value_t
*tv
= (omapi_value_t
*)0;
941 struct interface_info
*interface
;
946 /* First see if we were sent a handle. */
947 status
= omapi_get_value_str (ref
, id
, "handle", &tv
);
948 if (status
== ISC_R_SUCCESS
) {
949 status
= omapi_handle_td_lookup (ip
, tv
-> value
);
951 omapi_value_dereference (&tv
, MDL
);
952 if (status
!= ISC_R_SUCCESS
)
955 /* Don't return the object if the type is wrong. */
956 if ((*ip
) -> type
!= dhcp_type_interface
) {
957 omapi_object_dereference (ip
, MDL
);
958 return ISC_R_INVALIDARG
;
962 /* Now look for an interface name. */
963 status
= omapi_get_value_str (ref
, id
, "name", &tv
);
964 if (status
== ISC_R_SUCCESS
) {
967 for (interface
= interfaces
; interface
;
968 interface
= interface
-> next
) {
969 s
= memchr (interface
-> name
, 0, IFNAMSIZ
);
971 len
= s
- &interface
-> name
[0];
974 if ((tv
-> value
-> u
.buffer
.len
== len
&&
975 !memcmp (interface
-> name
,
976 (char *)tv
-> value
-> u
.buffer
.value
,
981 for (interface
= dummy_interfaces
;
982 interface
; interface
= interface
-> next
) {
983 s
= memchr (interface
-> name
, 0, IFNAMSIZ
);
985 len
= s
- &interface
-> name
[0];
988 if ((tv
-> value
-> u
.buffer
.len
== len
&&
989 !memcmp (interface
-> name
,
991 tv
-> value
-> u
.buffer
.value
,
997 omapi_value_dereference (&tv
, MDL
);
998 if (*ip
&& *ip
!= (omapi_object_t
*)interface
) {
999 omapi_object_dereference (ip
, MDL
);
1000 return ISC_R_KEYCONFLICT
;
1001 } else if (!interface
) {
1003 omapi_object_dereference (ip
, MDL
);
1004 return ISC_R_NOTFOUND
;
1006 omapi_object_reference (ip
,
1007 (omapi_object_t
*)interface
,
1011 /* If we get to here without finding an interface, no valid key was
1014 return ISC_R_NOKEYS
;
1015 return ISC_R_SUCCESS
;
1018 /* actually just go discover the interface */
1019 isc_result_t
dhcp_interface_create (omapi_object_t
**lp
,
1022 struct interface_info
*hp
;
1023 isc_result_t status
;
1025 hp
= (struct interface_info
*)0;
1026 status
= interface_allocate (&hp
, MDL
);
1027 if (status
!= ISC_R_SUCCESS
)
1029 hp
-> flags
= INTERFACE_REQUESTED
;
1030 status
= interface_reference ((struct interface_info
**)lp
, hp
, MDL
);
1031 interface_dereference (&hp
, MDL
);
1035 isc_result_t
dhcp_interface_remove (omapi_object_t
*lp
,
1038 struct interface_info
*interface
, *ip
, *last
;
1040 interface
= (struct interface_info
*)lp
;
1042 /* remove from interfaces */
1044 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
1045 if (ip
== interface
) {
1047 interface_dereference (&last
-> next
, MDL
);
1049 interface_reference (&last
-> next
,
1052 interface_dereference (&interfaces
, MDL
);
1054 interface_reference (&interfaces
,
1058 interface_dereference (&ip
-> next
, MDL
);
1064 return ISC_R_NOTFOUND
;
1066 /* add the interface to the dummy_interface list */
1067 if (dummy_interfaces
) {
1068 interface_reference (&interface
-> next
,
1069 dummy_interfaces
, MDL
);
1070 interface_dereference (&dummy_interfaces
, MDL
);
1072 interface_reference (&dummy_interfaces
, interface
, MDL
);
1074 /* do a DHCPRELEASE */
1075 if (dhcp_interface_shutdown_hook
)
1076 (*dhcp_interface_shutdown_hook
) (interface
);
1078 /* remove the io object */
1079 omapi_unregister_io_object ((omapi_object_t
*)interface
);
1081 if_deregister_send (interface
);
1082 if_deregister_receive (interface
);
1084 return ISC_R_SUCCESS
;
1087 void interface_stash (struct interface_info
*tptr
)
1089 struct interface_info
**vec
;
1092 /* If the registerer didn't assign an index, assign one now. */
1093 if (tptr
-> index
== -1) {
1094 tptr
-> index
= interface_count
++;
1095 while (tptr
-> index
< interface_max
&&
1096 interface_vector
[tptr
-> index
])
1097 tptr
-> index
= interface_count
++;
1100 if (interface_max
<= tptr
-> index
) {
1101 delta
= tptr
-> index
- interface_max
+ 10;
1102 vec
= dmalloc ((interface_max
+ delta
) *
1103 sizeof (struct interface_info
*), MDL
);
1106 memset (&vec
[interface_max
], 0,
1107 (sizeof (struct interface_info
*)) * delta
);
1108 interface_max
+= delta
;
1109 if (interface_vector
) {
1110 memcpy (vec
, interface_vector
,
1112 sizeof (struct interface_info
*)));
1113 dfree (interface_vector
, MDL
);
1115 interface_vector
= vec
;
1117 interface_reference (&interface_vector
[tptr
-> index
], tptr
, MDL
);
1118 if (tptr
-> index
>= interface_count
)
1119 interface_count
= tptr
-> index
+ 1;
1120 #if defined (TRACING)
1121 trace_interface_register (interface_trace
, tptr
);
1125 void interface_snorf (struct interface_info
*tmp
, int ir
)
1127 tmp
-> circuit_id
= (u_int8_t
*)tmp
-> name
;
1128 tmp
-> circuit_id_len
= strlen (tmp
-> name
);
1129 tmp
-> remote_id
= 0;
1130 tmp
-> remote_id_len
= 0;
1133 interface_reference (&tmp
-> next
,
1135 interface_dereference (&interfaces
, MDL
);
1137 interface_reference (&interfaces
, tmp
, MDL
);