3 Network input dispatcher... */
6 * Copyright (c) 1995-2002 Internet Software Consortium.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of The Internet Software Consortium nor the names
19 * of its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23 * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * This software has been written for the Internet Software Consortium
37 * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38 * To learn more about the Internet Software Consortium, see
39 * ``http://www.isc.org/''. To learn more about Vixie Enterprises,
40 * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
41 * ``http://www.nominum.com''.
43 * $Id: discover.c,v 1.42.2.14 2003/07/25 19:44:15 dhankins Exp $ Copyright (c) 1995-2002 The Internet Software Consortium. All rights reserved.
44 * $DragonFly: src/contrib/isc-dhcp/common/Attic/discover.c,v 1.2 2003/10/11 21:14:17 dillon Exp $
48 #include <sys/ioctl.h>
50 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
51 int interfaces_invalidated;
52 int quiet_interface_discovery;
54 u_int16_t remote_port;
55 int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
56 int (*dhcp_interface_discovery_hook) (struct interface_info *);
57 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
58 int (*dhcp_interface_shutdown_hook) (struct interface_info *);
60 struct in_addr limited_broadcast;
61 struct in_addr local_address;
63 void (*bootp_packet_handler) PROTO ((struct interface_info *,
64 struct dhcp_packet *, unsigned,
66 struct iaddr, struct hardware *));
68 omapi_object_type_t *dhcp_type_interface;
70 trace_type_t *interface_trace;
71 trace_type_t *inpacket_trace;
72 trace_type_t *outpacket_trace;
74 struct interface_info **interface_vector;
78 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
80 isc_result_t interface_setup ()
83 status = omapi_object_type_register (&dhcp_type_interface,
85 dhcp_interface_set_value,
86 dhcp_interface_get_value,
87 dhcp_interface_destroy,
88 dhcp_interface_signal_handler,
89 dhcp_interface_stuff_values,
90 dhcp_interface_lookup,
91 dhcp_interface_create,
92 dhcp_interface_remove,
94 sizeof (struct interface_info),
95 interface_initialize, RC_MISC);
96 if (status != ISC_R_SUCCESS)
97 log_fatal ("Can't register interface object type: %s",
98 isc_result_totext (status));
103 #if defined (TRACING)
104 void interface_trace_setup ()
106 interface_trace = trace_type_register ("interface", (void *)0,
107 trace_interface_input,
108 trace_interface_stop, MDL);
109 inpacket_trace = trace_type_register ("inpacket", (void *)0,
110 trace_inpacket_input,
111 trace_inpacket_stop, MDL);
112 outpacket_trace = trace_type_register ("outpacket", (void *)0,
113 trace_outpacket_input,
114 trace_outpacket_stop, MDL);
118 isc_result_t interface_initialize (omapi_object_t *ipo,
119 const char *file, int line)
121 struct interface_info *ip = (struct interface_info *)ipo;
122 ip -> rfdesc = ip -> wfdesc = -1;
123 return ISC_R_SUCCESS;
126 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
127 For each interface that's of type INET and not the loopback interface,
128 register that interface with the network I/O software, figure out what
129 subnet it's on, and add it to the list of interfaces. */
131 void discover_interfaces (state)
134 struct interface_info *tmp, *ip;
135 struct interface_info *last, *next;
141 int address_count = 0;
142 struct subnet *subnet;
143 struct shared_network *share;
144 struct sockaddr_in foo;
147 #ifdef ALIAS_NAMES_PERMUTED
151 static int setup_fallback = 0;
154 /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
155 if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
156 log_fatal ("Can't create addrlist socket");
158 /* Get the interface configuration information... */
160 #ifdef SIOCGIFCONF_ZERO_PROBE
161 /* linux will only tell us how long a buffer it wants if we give it
162 * a null buffer first. So, do a dry run to figure out the length.
164 * XXX this code is duplicated from below because trying to fold
165 * the logic into the if statement and goto resulted in excesssive
166 * obfuscation. The intent is that unless you run Linux you shouldn't
167 * have to deal with this. */
170 ic.ifc_ifcu.ifcu_buf = (caddr_t)NULL;
172 /* otherwise, we just feed it a starting size, and it'll tell us if
175 ic.ifc_len = sizeof buf;
176 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
180 i = ioctl(sock, SIOCGIFCONF, &ic);
183 log_fatal ("ioctl: SIOCGIFCONF: %m");
185 #ifdef SIOCGIFCONF_ZERO_PROBE
186 /* Workaround for SIOCGIFCONF bug on some Linux versions. */
187 if (ic.ifc_ifcu.ifcu_buf == 0 && ic.ifc_len == 0) {
188 ic.ifc_len = sizeof buf;
189 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
194 /* If the SIOCGIFCONF resulted in more data than would fit in
195 a buffer, allocate a bigger buffer. */
196 if ((ic.ifc_ifcu.ifcu_buf == buf
197 #ifdef SIOCGIFCONF_ZERO_PROBE
198 || ic.ifc_ifcu.ifcu_buf == 0
200 ) && ic.ifc_len > sizeof buf) {
201 ic.ifc_ifcu.ifcu_buf = dmalloc ((size_t)ic.ifc_len, MDL);
202 if (!ic.ifc_ifcu.ifcu_buf)
203 log_fatal ("Can't allocate SIOCGIFCONF buffer.");
205 #ifdef SIOCGIFCONF_ZERO_PROBE
206 } else if (ic.ifc_ifcu.ifcu_buf == 0) {
207 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
208 ic.ifc_len = sizeof buf;
214 /* If we already have a list of interfaces, and we're running as
215 a DHCP server, the interfaces were requested. */
216 if (interfaces && (state == DISCOVER_SERVER ||
217 state == DISCOVER_RELAY ||
218 state == DISCOVER_REQUESTED))
220 else if (state == DISCOVER_UNCONFIGURED)
221 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
223 ir = INTERFACE_REQUESTED;
225 /* Cycle through the list of interfaces looking for IP addresses. */
226 for (i = 0; i < ic.ifc_len;) {
227 struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
229 if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr))
230 i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
235 #ifdef ALIAS_NAMES_PERMUTED
236 if ((s = strrchr (ifp -> ifr_name, ':'))) {
241 #ifdef SKIP_DUMMY_INTERFACES
242 if (!strncmp (ifp -> ifr_name, "dummy", 5))
247 /* See if this is the sort of interface we want to
249 strcpy (ifr.ifr_name, ifp -> ifr_name);
250 if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
251 log_fatal ("Can't get interface flags for %s: %m",
254 /* See if we've seen an interface that matches this one. */
255 for (tmp = interfaces; tmp; tmp = tmp -> next)
256 if (!strcmp (tmp -> name, ifp -> ifr_name))
259 /* Skip non broadcast interfaces (plus loopback and
260 point-to-point in case an OS incorrectly marks them
261 as broadcast). Also skip down interfaces unless we're
262 trying to get a list of configurable interfaces. */
263 if (((!(ifr.ifr_flags & IFF_BROADCAST) ||
264 ifr.ifr_flags & IFF_LOOPBACK ||
265 ifr.ifr_flags & IFF_POINTOPOINT) && !tmp) ||
266 (!(ifr.ifr_flags & IFF_UP) &&
267 state != DISCOVER_UNCONFIGURED))
270 /* If there isn't already an interface by this name,
273 tmp = (struct interface_info *)0;
274 status = interface_allocate (&tmp, MDL);
275 if (status != ISC_R_SUCCESS)
276 log_fatal ("Error allocating interface %s: %s",
278 isc_result_totext (status));
279 strcpy (tmp -> name, ifp -> ifr_name);
280 interface_snorf (tmp, ir);
281 interface_dereference (&tmp, MDL);
282 tmp = interfaces; /* XXX */
285 if (dhcp_interface_discovery_hook)
286 (*dhcp_interface_discovery_hook) (tmp);
288 /* If we have the capability, extract link information
289 and record it in a linked list. */
291 if (ifp -> ifr_addr.sa_family == AF_LINK) {
292 struct sockaddr_dl *foo = ((struct sockaddr_dl *)
294 #if defined (HAVE_SIN_LEN)
295 tmp -> hw_address.hlen = foo -> sdl_alen;
297 tmp -> hw_address.hlen = 6; /* XXX!!! */
299 tmp -> hw_address.hbuf [0] = HTYPE_ETHER; /* XXX */
300 memcpy (&tmp -> hw_address.hbuf [1],
301 LLADDR (foo), tmp -> hw_address.hlen);
302 tmp -> hw_address.hlen++; /* for type. */
306 if (ifp -> ifr_addr.sa_family == AF_INET) {
309 /* Get a pointer to the address... */
310 memcpy (&foo, &ifp -> ifr_addr,
311 sizeof ifp -> ifr_addr);
313 /* We don't want the loopback interface. */
314 if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK) &&
315 ((tmp -> flags & INTERFACE_AUTOMATIC) &&
316 state == DISCOVER_SERVER))
320 /* If this is the first real IP address we've
321 found, keep a pointer to ifreq structure in
322 which we found it. */
325 unsigned len = ((sizeof ifp -> ifr_name) +
326 ifp -> ifr_addr.sa_len);
328 unsigned len = sizeof *ifp;
330 tif = (struct ifreq *)dmalloc (len, MDL);
332 log_fatal ("no space for ifp.");
333 memcpy (tif, ifp, len);
335 tmp -> primary_address = foo.sin_addr;
338 /* Grab the address... */
340 memcpy (addr.iabuf, &foo.sin_addr.s_addr,
342 if (dhcp_interface_setup_hook)
343 (*dhcp_interface_setup_hook) (tmp, &addr);
347 /* If we allocated a buffer, free it. */
348 if (ic.ifc_ifcu.ifcu_buf != buf)
349 dfree (ic.ifc_ifcu.ifcu_buf, MDL);
351 #if defined (LINUX_SLASHPROC_DISCOVERY)
352 /* On Linux, interfaces that don't have IP addresses don't
353 show up in the SIOCGIFCONF syscall. This only matters for
354 the DHCP client, of course - the relay agent and server
355 should only care about interfaces that are configured with
358 The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
359 that, when read, prints a human readable network status. We
360 extract the names of the network devices by skipping the first
361 two lines (which are header) and then parsing off everything
362 up to the colon in each subsequent line - these lines start
363 with the interface name, then a colon, then a bunch of
366 if (state == DISCOVER_UNCONFIGURED) {
371 proc_dev = fopen (PROCDEV_DEVICE, "r");
373 log_fatal ("%s: %m", PROCDEV_DEVICE);
375 while (fgets (buffer, sizeof buffer, proc_dev)) {
379 /* Skip the first two blocks, which are header
386 sep = strrchr (buffer, ':');
392 /* See if we've seen an interface that matches
394 for (tmp = interfaces; tmp; tmp = tmp -> next)
395 if (!strcmp (tmp -> name, name))
398 /* If we found one, nothing more to do.. */
402 /* Otherwise, allocate one. */
403 tmp = (struct interface_info *)0;
404 status = interface_allocate (&tmp, MDL);
405 if (status != ISC_R_SUCCESS)
406 log_fatal ("Can't allocate interface %s: %s",
407 name, isc_result_totext (status));
409 strncpy (tmp -> name, name, IFNAMSIZ);
411 interface_reference (&tmp -> next,
413 interface_dereference (&interfaces, MDL);
415 interface_reference (&interfaces, tmp, MDL);
416 interface_dereference (&tmp, MDL);
419 if (dhcp_interface_discovery_hook)
420 (*dhcp_interface_discovery_hook) (tmp);
427 /* Now cycle through all the interfaces we found, looking for
428 hardware addresses. */
429 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
430 for (tmp = interfaces; tmp; tmp = tmp -> next) {
436 /* Make up an ifreq structure. */
437 tif = (struct ifreq *)dmalloc (sizeof (struct ifreq),
440 log_fatal ("no space to remember ifp.");
441 memset (tif, 0, sizeof (struct ifreq));
442 strcpy (tif -> ifr_name, tmp -> name);
446 /* Read the hardware address from this interface. */
448 if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
451 sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
453 switch (sa.sa_family) {
454 #ifdef HAVE_ARPHRD_TUNNEL
456 /* ignore tunnel interfaces. */
458 #ifdef HAVE_ARPHRD_ROSE
461 #ifdef HAVE_ARPHRD_LOOPBACK
462 case ARPHRD_LOOPBACK:
463 /* ignore loopback interface */
468 tmp -> hw_address.hlen = 7;
469 tmp -> hw_address.hbuf [0] = ARPHRD_ETHER;
470 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
473 #ifndef HAVE_ARPHRD_IEEE802
474 # define ARPHRD_IEEE802 HTYPE_IEEE802
476 #if defined (HAVE_ARPHRD_IEEE802_TR)
477 case ARPHRD_IEEE802_TR:
480 tmp -> hw_address.hlen = 7;
481 tmp -> hw_address.hbuf [0] = ARPHRD_IEEE802;
482 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
485 #ifndef HAVE_ARPHRD_FDDI
486 # define ARPHRD_FDDI HTYPE_FDDI
489 tmp -> hw_address.hlen = 17;
490 tmp -> hw_address.hbuf [0] = HTYPE_FDDI; /* XXX */
491 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 16);
494 #ifdef HAVE_ARPHRD_METRICOM
495 case ARPHRD_METRICOM:
496 tmp -> hw_address.hlen = 7;
497 tmp -> hw_address.hbuf [0] = ARPHRD_METRICOM;
498 memcpy (&tmp -> hw_address.hbuf [0], sa.sa_data, 6);
502 #ifdef HAVE_ARPHRD_AX25
504 tmp -> hw_address.hlen = 7;
505 tmp -> hw_address.hbuf [0] = ARPHRD_AX25;
506 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
510 #ifdef HAVE_ARPHRD_NETROM
512 tmp -> hw_address.hlen = 7;
513 tmp -> hw_address.hbuf [0] = ARPHRD_NETROM;
514 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
519 log_error ("%s: unknown hardware address type %d",
520 ifr.ifr_name, sa.sa_family);
524 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
526 /* If we're just trying to get a list of interfaces that we might
527 be able to configure, we can quit now. */
528 if (state == DISCOVER_UNCONFIGURED) {
533 /* Weed out the interfaces that did not have IP addresses. */
534 tmp = last = next = (struct interface_info *)0;
536 interface_reference (&tmp, interfaces, MDL);
539 interface_dereference (&next, MDL);
541 interface_reference (&next, tmp -> next, MDL);
542 /* skip interfaces that are running already */
543 if (tmp -> flags & INTERFACE_RUNNING) {
544 interface_dereference(&tmp, MDL);
546 interface_reference(&tmp, next, MDL);
549 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
550 state == DISCOVER_REQUESTED)
551 tmp -> flags &= ~(INTERFACE_AUTOMATIC |
552 INTERFACE_REQUESTED);
553 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
554 if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
555 log_fatal ("%s: not found", tmp -> name);
558 interface_dereference (&interfaces,
561 interface_reference (&interfaces, next, MDL);
563 interface_dereference (&last -> next, MDL);
565 interface_reference (&last -> next,
569 interface_dereference (&tmp -> next, MDL);
571 /* Remember the interface in case we need to know
573 if (dummy_interfaces) {
574 interface_reference (&tmp -> next,
575 dummy_interfaces, MDL);
576 interface_dereference (&dummy_interfaces, MDL);
578 interface_reference (&dummy_interfaces, tmp, MDL);
579 interface_dereference (&tmp, MDL);
581 interface_reference (&tmp, next, MDL);
586 memcpy (&foo, &tmp -> ifp -> ifr_addr,
587 sizeof tmp -> ifp -> ifr_addr);
589 /* We must have a subnet declaration for each interface. */
590 if (!tmp -> shared_network && (state == DISCOVER_SERVER)) {
591 log_error ("%s", "");
592 log_error ("No subnet declaration for %s (%s).",
593 tmp -> name, inet_ntoa (foo.sin_addr));
594 if (supports_multiple_interfaces (tmp)) {
595 log_error ("** Ignoring requests on %s. %s",
596 tmp -> name, "If this is not what");
597 log_error (" you want, please write %s",
598 "a subnet declaration");
599 log_error (" in your dhcpd.conf file %s",
600 "for the network segment");
601 log_error (" to %s %s %s",
603 tmp -> name, "is attached. **");
604 log_error ("%s", "");
607 log_error ("You must write a subnet %s",
608 " declaration for this");
609 log_error ("subnet. You cannot prevent %s",
611 log_error ("from listening on this subnet %s",
613 log_fatal ("operating system does not %s.",
614 "support this capability");
618 /* Find subnets that don't have valid interface
620 for (subnet = (tmp -> shared_network
621 ? tmp -> shared_network -> subnets
622 : (struct subnet *)0);
623 subnet; subnet = subnet -> next_sibling) {
624 if (!subnet -> interface_address.len) {
625 /* Set the interface address for this subnet
626 to the first address we found. */
627 subnet -> interface_address.len = 4;
628 memcpy (subnet -> interface_address.iabuf,
629 &foo.sin_addr.s_addr, 4);
633 /* Flag the index as not having been set, so that the
634 interface registerer can set it or not as it chooses. */
637 /* Register the interface... */
638 if_register_receive (tmp);
639 if_register_send (tmp);
641 interface_stash (tmp);
643 #if defined (HAVE_SETFD)
644 if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0)
645 log_error ("Can't set close-on-exec on %s: %m",
647 if (tmp -> rfdesc != tmp -> wfdesc) {
648 if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0)
649 log_error ("Can't set close-on-exec on %s: %m",
654 interface_dereference (&tmp, MDL);
656 interface_reference (&tmp, next, MDL);
659 /* Now register all the remaining interfaces as protocols. */
660 for (tmp = interfaces; tmp; tmp = tmp -> next) {
661 /* not if it's been registered before */
662 if (tmp -> flags & INTERFACE_RUNNING)
664 if (tmp -> rfdesc == -1)
666 status = omapi_register_io_object ((omapi_object_t *)tmp,
669 if (status != ISC_R_SUCCESS)
670 log_fatal ("Can't register I/O handle for %s: %s",
671 tmp -> name, isc_result_totext (status));
676 if (state == DISCOVER_SERVER && wifcount == 0) {
678 log_fatal ("Not configured to listen on any interfaces!");
681 if (!setup_fallback) {
683 maybe_setup_fallback ();
686 #if defined (HAVE_SETFD)
687 if (fallback_interface) {
688 if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
689 log_error ("Can't set close-on-exec on fallback: %m");
690 if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
691 if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
692 log_error ("Can't set close-on-exec on fallback: %m");
698 int if_readsocket (h)
701 struct interface_info *ip;
703 if (h -> type != dhcp_type_interface)
705 ip = (struct interface_info *)h;
709 int setup_fallback (struct interface_info **fp, const char *file, int line)
713 status = interface_allocate (&fallback_interface, file, line);
714 if (status != ISC_R_SUCCESS)
715 log_fatal ("Error allocating fallback interface: %s",
716 isc_result_totext (status));
717 strcpy (fallback_interface -> name, "fallback");
718 if (dhcp_interface_setup_hook)
719 (*dhcp_interface_setup_hook) (fallback_interface,
721 status = interface_reference (fp, fallback_interface, file, line);
723 fallback_interface -> index = -1;
724 interface_stash (fallback_interface);
725 return status == ISC_R_SUCCESS;
728 void reinitialize_interfaces ()
730 struct interface_info *ip;
732 for (ip = interfaces; ip; ip = ip -> next) {
733 if_reinitialize_receive (ip);
734 if_reinitialize_send (ip);
737 if (fallback_interface)
738 if_reinitialize_send (fallback_interface);
740 interfaces_invalidated = 1;
743 isc_result_t got_one (h)
746 struct sockaddr_in from;
747 struct hardware hfrom;
751 unsigned char packbuf [4095]; /* Packet input buffer.
752 Must be as large as largest
754 struct dhcp_packet packet;
756 struct interface_info *ip;
758 if (h -> type != dhcp_type_interface)
759 return ISC_R_INVALIDARG;
760 ip = (struct interface_info *)h;
764 receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
765 log_error ("receive_packet failed on %s: %m", ip -> name);
766 return ISC_R_UNEXPECTED;
769 return ISC_R_UNEXPECTED;
771 /* If we didn't at least get the fixed portion of the BOOTP
772 packet, drop the packet. We're allowing packets with no
773 sname or filename, because we're aware of at least one
774 client that sends such packets, but this definitely falls
775 into the category of being forgiving. */
776 if (result < DHCP_FIXED_NON_UDP - DHCP_SNAME_LEN - DHCP_FILE_LEN)
777 return ISC_R_UNEXPECTED;
779 if (bootp_packet_handler) {
781 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
783 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
784 from.sin_port, ifrom, &hfrom);
787 /* If there is buffered data, read again. This is for, e.g.,
788 bpf, which may return two packets at once. */
789 if (ip -> rbuf_offset != ip -> rbuf_len)
791 return ISC_R_SUCCESS;
794 isc_result_t dhcp_interface_set_value (omapi_object_t *h,
796 omapi_data_string_t *name,
797 omapi_typed_data_t *value)
799 struct interface_info *interface;
803 if (h -> type != dhcp_type_interface)
804 return ISC_R_INVALIDARG;
805 interface = (struct interface_info *)h;
807 if (!omapi_ds_strcmp (name, "name")) {
808 if ((value -> type == omapi_datatype_data ||
809 value -> type == omapi_datatype_string) &&
810 value -> u.buffer.len < sizeof interface -> name) {
811 memcpy (interface -> name,
812 value -> u.buffer.value,
813 value -> u.buffer.len);
814 interface -> name [value -> u.buffer.len] = 0;
816 return ISC_R_INVALIDARG;
817 return ISC_R_SUCCESS;
820 /* Try to find some inner object that can take the value. */
821 if (h -> inner && h -> inner -> type -> set_value) {
822 status = ((*(h -> inner -> type -> set_value))
823 (h -> inner, id, name, value));
824 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
828 return ISC_R_NOTFOUND;
832 isc_result_t dhcp_interface_get_value (omapi_object_t *h,
834 omapi_data_string_t *name,
835 omapi_value_t **value)
837 return ISC_R_NOTIMPLEMENTED;
840 isc_result_t dhcp_interface_destroy (omapi_object_t *h,
841 const char *file, int line)
843 struct interface_info *interface;
846 if (h -> type != dhcp_type_interface)
847 return ISC_R_INVALIDARG;
848 interface = (struct interface_info *)h;
850 if (interface -> ifp) {
851 dfree (interface -> ifp, file, line);
852 interface -> ifp = 0;
854 if (interface -> next)
855 interface_dereference (&interface -> next, file, line);
856 if (interface -> rbuf) {
857 dfree (interface -> rbuf, file, line);
858 interface -> rbuf = (unsigned char *)0;
860 if (interface -> client)
861 interface -> client = (struct client_state *)0;
863 if (interface -> shared_network)
864 omapi_object_dereference ((omapi_object_t **)
865 &interface -> shared_network, MDL);
867 return ISC_R_SUCCESS;
870 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
871 const char *name, va_list ap)
873 struct interface_info *ip, *interface;
874 struct client_config *config;
875 struct client_state *client;
878 if (h -> type != dhcp_type_interface)
879 return ISC_R_INVALIDARG;
880 interface = (struct interface_info *)h;
882 /* If it's an update signal, see if the interface is dead right
883 now, or isn't known at all, and if that's the case, revive it. */
884 if (!strcmp (name, "update")) {
885 for (ip = dummy_interfaces; ip; ip = ip -> next)
888 if (ip && dhcp_interface_startup_hook)
889 return (*dhcp_interface_startup_hook) (ip);
891 for (ip = interfaces; ip; ip = ip -> next)
894 if (!ip && dhcp_interface_startup_hook)
895 return (*dhcp_interface_startup_hook) (ip);
898 /* Try to find some inner object that can take the value. */
899 if (h -> inner && h -> inner -> type -> get_value) {
900 status = ((*(h -> inner -> type -> signal_handler))
901 (h -> inner, name, ap));
902 if (status == ISC_R_SUCCESS)
905 return ISC_R_NOTFOUND;
908 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
912 struct interface_info *interface;
915 if (h -> type != dhcp_type_interface)
916 return ISC_R_INVALIDARG;
917 interface = (struct interface_info *)h;
919 /* Write out all the values. */
921 status = omapi_connection_put_name (c, "state");
922 if (status != ISC_R_SUCCESS)
924 if (interface -> flags && INTERFACE_REQUESTED)
925 status = omapi_connection_put_string (c, "up");
927 status = omapi_connection_put_string (c, "down");
928 if (status != ISC_R_SUCCESS)
931 /* Write out the inner object, if any. */
932 if (h -> inner && h -> inner -> type -> stuff_values) {
933 status = ((*(h -> inner -> type -> stuff_values))
934 (c, id, h -> inner));
935 if (status == ISC_R_SUCCESS)
939 return ISC_R_SUCCESS;
942 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
946 omapi_value_t *tv = (omapi_value_t *)0;
948 struct interface_info *interface;
953 /* First see if we were sent a handle. */
954 status = omapi_get_value_str (ref, id, "handle", &tv);
955 if (status == ISC_R_SUCCESS) {
956 status = omapi_handle_td_lookup (ip, tv -> value);
958 omapi_value_dereference (&tv, MDL);
959 if (status != ISC_R_SUCCESS)
962 /* Don't return the object if the type is wrong. */
963 if ((*ip) -> type != dhcp_type_interface) {
964 omapi_object_dereference (ip, MDL);
965 return ISC_R_INVALIDARG;
969 /* Now look for an interface name. */
970 status = omapi_get_value_str (ref, id, "name", &tv);
971 if (status == ISC_R_SUCCESS) {
974 for (interface = interfaces; interface;
975 interface = interface -> next) {
976 s = memchr (interface -> name, 0, IFNAMSIZ);
978 len = s - &interface -> name [0];
981 if ((tv -> value -> u.buffer.len == len &&
982 !memcmp (interface -> name,
983 (char *)tv -> value -> u.buffer.value,
988 for (interface = dummy_interfaces;
989 interface; interface = interface -> next) {
990 s = memchr (interface -> name, 0, IFNAMSIZ);
992 len = s - &interface -> name [0];
995 if ((tv -> value -> u.buffer.len == len &&
996 !memcmp (interface -> name,
998 tv -> value -> u.buffer.value,
1004 omapi_value_dereference (&tv, MDL);
1005 if (*ip && *ip != (omapi_object_t *)interface) {
1006 omapi_object_dereference (ip, MDL);
1007 return ISC_R_KEYCONFLICT;
1008 } else if (!interface) {
1010 omapi_object_dereference (ip, MDL);
1011 return ISC_R_NOTFOUND;
1013 omapi_object_reference (ip,
1014 (omapi_object_t *)interface,
1018 /* If we get to here without finding an interface, no valid key was
1021 return ISC_R_NOKEYS;
1022 return ISC_R_SUCCESS;
1025 /* actually just go discover the interface */
1026 isc_result_t dhcp_interface_create (omapi_object_t **lp,
1029 struct interface_info *hp;
1030 isc_result_t status;
1032 hp = (struct interface_info *)0;
1033 status = interface_allocate (&hp, MDL);
1034 if (status != ISC_R_SUCCESS)
1036 hp -> flags = INTERFACE_REQUESTED;
1037 status = interface_reference ((struct interface_info **)lp, hp, MDL);
1038 interface_dereference (&hp, MDL);
1042 isc_result_t dhcp_interface_remove (omapi_object_t *lp,
1045 struct interface_info *interface, *ip, *last;
1047 interface = (struct interface_info *)lp;
1049 /* remove from interfaces */
1051 for (ip = interfaces; ip; ip = ip -> next) {
1052 if (ip == interface) {
1054 interface_dereference (&last -> next, MDL);
1056 interface_reference (&last -> next,
1059 interface_dereference (&interfaces, MDL);
1061 interface_reference (&interfaces,
1065 interface_dereference (&ip -> next, MDL);
1071 return ISC_R_NOTFOUND;
1073 /* add the interface to the dummy_interface list */
1074 if (dummy_interfaces) {
1075 interface_reference (&interface -> next,
1076 dummy_interfaces, MDL);
1077 interface_dereference (&dummy_interfaces, MDL);
1079 interface_reference (&dummy_interfaces, interface, MDL);
1081 /* do a DHCPRELEASE */
1082 if (dhcp_interface_shutdown_hook)
1083 (*dhcp_interface_shutdown_hook) (interface);
1085 /* remove the io object */
1086 omapi_unregister_io_object ((omapi_object_t *)interface);
1088 if_deregister_send (interface);
1089 if_deregister_receive (interface);
1091 return ISC_R_SUCCESS;
1094 void interface_stash (struct interface_info *tptr)
1096 struct interface_info **vec;
1099 /* If the registerer didn't assign an index, assign one now. */
1100 if (tptr -> index == -1) {
1101 tptr -> index = interface_count++;
1102 while (tptr -> index < interface_max &&
1103 interface_vector [tptr -> index])
1104 tptr -> index = interface_count++;
1107 if (interface_max <= tptr -> index) {
1108 delta = tptr -> index - interface_max + 10;
1109 vec = dmalloc ((interface_max + delta) *
1110 sizeof (struct interface_info *), MDL);
1113 memset (&vec [interface_max], 0,
1114 (sizeof (struct interface_info *)) * delta);
1115 interface_max += delta;
1116 if (interface_vector) {
1117 memcpy (vec, interface_vector,
1119 sizeof (struct interface_info *)));
1120 dfree (interface_vector, MDL);
1122 interface_vector = vec;
1124 interface_reference (&interface_vector [tptr -> index], tptr, MDL);
1125 if (tptr -> index >= interface_count)
1126 interface_count = tptr -> index + 1;
1127 #if defined (TRACING)
1128 trace_interface_register (interface_trace, tptr);
1132 void interface_snorf (struct interface_info *tmp, int ir)
1134 tmp -> circuit_id = (u_int8_t *)tmp -> name;
1135 tmp -> circuit_id_len = strlen (tmp -> name);
1136 tmp -> remote_id = 0;
1137 tmp -> remote_id_len = 0;
1140 interface_reference (&tmp -> next,
1142 interface_dereference (&interfaces, MDL);
1144 interface_reference (&interfaces, tmp, MDL);