Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / dhcp / common / discover.c
blobf0fd9f08072ef4ac1ee3b60534e3ed9481396eda
1 /* dispatch.c
3 Network input dispatcher... */
5 /*
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.
22 * 950 Charter Street
23 * Redwood City, CA 94063
24 * <info@isc.org>
25 * http://www.isc.org/
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''.
35 #ifndef lint
36 static char copyright[] =
37 "$Id: discover.c,v 1.11 2007/10/31 15:26:51 gdt Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
38 #endif /* not lint */
40 #include "dhcpd.h"
41 #include <sys/ioctl.h>
42 #include <stddef.h>
44 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
45 int interfaces_invalidated;
46 int quiet_interface_discovery;
47 u_int16_t local_port;
48 u_int16_t remote_port;
49 int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
50 int (*dhcp_interface_discovery_hook) (struct interface_info *);
51 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
52 int (*dhcp_interface_shutdown_hook) (struct interface_info *);
54 struct in_addr limited_broadcast;
55 struct in_addr local_address;
57 void (*bootp_packet_handler) PROTO ((struct interface_info *,
58 struct dhcp_packet *, unsigned,
59 unsigned int,
60 struct iaddr, struct hardware *));
62 omapi_object_type_t *dhcp_type_interface;
63 #if defined (TRACING)
64 trace_type_t *interface_trace;
65 trace_type_t *inpacket_trace;
66 trace_type_t *outpacket_trace;
67 #endif
68 struct interface_info **interface_vector;
69 int interface_count;
70 int interface_max;
72 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
74 isc_result_t interface_setup ()
76 isc_result_t status;
77 status = omapi_object_type_register (&dhcp_type_interface,
78 "interface",
79 #ifdef SMALL
80 NULL,
81 NULL,
82 NULL,
83 NULL,
84 NULL,
85 NULL,
86 NULL,
87 NULL,
88 #else
89 dhcp_interface_set_value,
90 dhcp_interface_get_value,
91 dhcp_interface_destroy,
92 dhcp_interface_signal_handler,
93 dhcp_interface_stuff_values,
94 dhcp_interface_lookup,
95 dhcp_interface_create,
96 dhcp_interface_remove,
97 #endif
98 0, 0, 0,
99 sizeof (struct interface_info),
100 interface_initialize, RC_MISC);
101 if (status != ISC_R_SUCCESS)
102 log_fatal ("Can't register interface object type: %s",
103 isc_result_totext (status));
105 return status;
108 #if defined (TRACING)
109 void interface_trace_setup ()
111 interface_trace = trace_type_register ("interface", (void *)0,
112 trace_interface_input,
113 trace_interface_stop, MDL);
114 inpacket_trace = trace_type_register ("inpacket", (void *)0,
115 trace_inpacket_input,
116 trace_inpacket_stop, MDL);
117 outpacket_trace = trace_type_register ("outpacket", (void *)0,
118 trace_outpacket_input,
119 trace_outpacket_stop, MDL);
121 #endif
123 isc_result_t interface_initialize (omapi_object_t *ipo,
124 const char *file, int line)
126 struct interface_info *ip = (struct interface_info *)ipo;
127 ip -> rfdesc = ip -> wfdesc = -1;
128 return ISC_R_SUCCESS;
131 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
132 For each interface that's of type INET and not the loopback interface,
133 register that interface with the network I/O software, figure out what
134 subnet it's on, and add it to the list of interfaces. */
136 void discover_interfaces (state)
137 int state;
139 struct interface_info *tmp;
140 struct interface_info *last, *next;
142 * Because the code to retry on SIOCGIFCONF not returning all
143 * interfaces is broken, use an unreasonably large buffer to
144 * handle the case of a machine with lots of (usually virtual)
145 * interfaces.
147 char buf [32768];
148 struct ifconf ic;
149 struct ifreq ifr;
150 int i;
151 int sock;
152 struct subnet *subnet;
153 struct sockaddr_in foo;
154 int ir;
155 struct ifreq *tif;
156 #ifdef ALIAS_NAMES_PERMUTED
157 char *s;
158 #endif
159 isc_result_t status;
160 static int setup_fallback = 0;
161 int wifcount = 0;
163 /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
164 if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
165 log_fatal ("Can't create addrlist socket");
167 /* Get the interface configuration information... */
169 #ifdef SIOCGIFCONF_ZERO_PROBE
170 /* linux will only tell us how long a buffer it wants if we give it
171 * a null buffer first. So, do a dry run to figure out the length.
173 * XXX this code is duplicated from below because trying to fold
174 * the logic into the if statement and goto resulted in excesssive
175 * obfuscation. The intent is that unless you run Linux you shouldn't
176 * have to deal with this. */
178 ic.ifc_len = 0;
179 ic.ifc_ifcu.ifcu_buf = (caddr_t)NULL;
180 #else
181 /* otherwise, we just feed it a starting size, and it'll tell us if
182 * it needs more */
184 ic.ifc_len = sizeof buf;
185 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
186 #endif
188 gifconf_again:
189 i = ioctl(sock, SIOCGIFCONF, &ic);
191 if (i < 0)
192 log_fatal ("ioctl: SIOCGIFCONF: %m");
194 #ifdef SIOCGIFCONF_ZERO_PROBE
195 /* Workaround for SIOCGIFCONF bug on some Linux versions. */
196 if (ic.ifc_ifcu.ifcu_buf == 0 && ic.ifc_len == 0) {
197 ic.ifc_len = sizeof buf;
198 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
199 goto gifconf_again;
201 #endif
203 /* If the SIOCGIFCONF resulted in more data than would fit in
204 a buffer, allocate a bigger buffer. */
206 * XXX This code is broken on NetBSD; the return value is the
207 * amount of data returned, not the amount that would be
208 * needed. We need to e.g. double the buffer and try again.
209 * The proper test is hairier: we can be sure that we got
210 * everything only if there is an entire struct ifreq worth of
211 * space left.
213 if ((ic.ifc_ifcu.ifcu_buf == buf
214 #ifdef SIOCGIFCONF_ZERO_PROBE
215 || ic.ifc_ifcu.ifcu_buf == 0
216 #endif
217 ) && ic.ifc_len > sizeof buf) {
218 ic.ifc_ifcu.ifcu_buf = dmalloc ((size_t)ic.ifc_len, MDL);
219 if (!ic.ifc_ifcu.ifcu_buf)
220 log_fatal ("Can't allocate SIOCGIFCONF buffer.");
221 goto gifconf_again;
222 #ifdef SIOCGIFCONF_ZERO_PROBE
223 } else if (ic.ifc_ifcu.ifcu_buf == 0) {
224 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
225 ic.ifc_len = sizeof buf;
226 goto gifconf_again;
227 #endif
231 /* If we already have a list of interfaces, and we're running as
232 a DHCP server, the interfaces were requested. */
233 if (interfaces && (state == DISCOVER_SERVER ||
234 state == DISCOVER_RELAY ||
235 state == DISCOVER_REQUESTED))
236 ir = 0;
237 else if (state == DISCOVER_UNCONFIGURED)
238 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
239 else
240 ir = INTERFACE_REQUESTED;
242 /* Cycle through the list of interfaces looking for IP addresses. */
243 for (i = 0; i < ic.ifc_len;) {
244 union {
245 struct ifreq ifr;
246 char buf[2000];
247 } ifcpy;
248 struct ifreq *ifp = &ifcpy.ifr;
250 memcpy(&ifcpy, (caddr_t)ic.ifc_req + i, sizeof(struct ifreq));
251 #ifdef HAVE_SA_LEN
253 * Classically, struct ifreq used with SIOCGIFCONF had
254 * a union where struct sockaddr was the largest
255 * member. If the address fit in the union, the next
256 * ifreq followed immediately. If not, the next ifreq
257 * followed the end of the actual sockaddr. In
258 * NetBSD-current after ~2007-05, ifreq has a
259 * sockaddr_storage member, and the next ifreq follows
260 * the current ifreq always, because no sockaddr can
261 * be bigger than sockaddr_storage. Thus, compare the
262 * length to the union's size, not struct sockaddr.
264 if (ifp -> ifr_addr.sa_len > sizeof (ifp->ifr_ifru)) {
265 if (sizeof(struct ifreq) + ifp->ifr_addr.sa_len >
266 sizeof(ifcpy))
267 break;
268 /* XXX This copies IFNAMSIZ bytes too many. */
269 memcpy(&ifcpy, (caddr_t)ic.ifc_req + i,
270 sizeof(struct ifreq) + ifp->ifr_addr.sa_len);
271 i += offsetof(struct ifreq, ifr_ifru) +
272 ifp -> ifr_addr.sa_len;
273 } else
274 #endif
275 i += sizeof *ifp;
277 #ifdef ALIAS_NAMES_PERMUTED
278 if ((s = strrchr (ifp -> ifr_name, ':'))) {
279 *s = 0;
281 #endif
283 #ifdef SKIP_DUMMY_INTERFACES
284 if (!strncmp (ifp -> ifr_name, "dummy", 5))
285 continue;
286 #endif
289 /* See if this is the sort of interface we want to
290 deal with. */
291 strcpy (ifr.ifr_name, ifp -> ifr_name);
292 if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
293 log_fatal ("Can't get interface flags for %s: %m",
294 ifr.ifr_name);
296 /* See if we've seen an interface that matches this one. */
297 for (tmp = interfaces; tmp; tmp = tmp -> next)
298 if (!strcmp (tmp -> name, ifp -> ifr_name))
299 break;
301 /* Skip non broadcast interfaces (plus loopback and
302 point-to-point in case an OS incorrectly marks them
303 as broadcast). Also skip down interfaces unless we're
304 trying to get a list of configurable interfaces. */
305 if (((!(ifr.ifr_flags & IFF_BROADCAST) ||
306 ifr.ifr_flags & IFF_LOOPBACK ||
307 ifr.ifr_flags & IFF_POINTOPOINT) && !tmp) ||
308 (!(ifr.ifr_flags & IFF_UP) &&
309 state != DISCOVER_UNCONFIGURED))
310 continue;
312 /* If there isn't already an interface by this name,
313 allocate one. */
314 if (!tmp) {
315 tmp = (struct interface_info *)0;
316 status = interface_allocate (&tmp, MDL);
317 if (status != ISC_R_SUCCESS)
318 log_fatal ("Error allocating interface %s: %s",
319 ifp -> ifr_name,
320 isc_result_totext (status));
321 strcpy (tmp -> name, ifp -> ifr_name);
322 interface_snorf (tmp, ir);
323 interface_dereference (&tmp, MDL);
324 tmp = interfaces; /* XXX */
327 if (dhcp_interface_discovery_hook)
328 (*dhcp_interface_discovery_hook) (tmp);
330 /* If we have the capability, extract link information
331 and record it in a linked list. */
332 #ifdef HAVE_AF_LINK
333 if (ifp -> ifr_addr.sa_family == AF_LINK) {
334 struct sockaddr_dl *foo = ((struct sockaddr_dl *)
335 (&ifp -> ifr_addr));
336 #if defined (HAVE_SIN_LEN)
337 tmp -> hw_address.hlen = foo -> sdl_alen;
338 #else
339 tmp -> hw_address.hlen = 6; /* XXX!!! */
340 #endif
341 if (foo -> sdl_type == IFT_ETHER) {
342 tmp -> hw_address.hbuf [0] = HTYPE_ETHER;
343 #if defined (DEC_FDDI) || defined(NETBSD_FDDI)
344 } else if (foo -> sdl_type == IFT_FDDI) {
345 tmp -> hw_address.hbuf [0] = HTYPE_FDDI;
346 #endif
347 } else {
348 continue;
350 memcpy (&tmp -> hw_address.hbuf [1],
351 LLADDR (foo), tmp -> hw_address.hlen);
352 tmp -> hw_address.hlen++; /* for type. */
353 } else
354 #endif /* AF_LINK */
356 if (ifp -> ifr_addr.sa_family == AF_INET) {
357 struct iaddr addr;
358 void *ptr;
360 /* Get a pointer to the address... */
361 ptr = &ifp -> ifr_addr;
362 memcpy (&foo, ptr, sizeof ifp -> ifr_addr);
364 /* We don't want the loopback interface. */
365 if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK) &&
366 ((tmp -> flags & INTERFACE_AUTOMATIC) &&
367 state == DISCOVER_SERVER))
368 continue;
371 /* If this is the first real IP address we've
372 found, keep a pointer to ifreq structure in
373 which we found it. */
374 if (!tmp -> ifp) {
375 #ifdef HAVE_SA_LEN
376 unsigned len = offsetof(struct ifreq, ifr_ifru)
377 + ifp -> ifr_addr.sa_len;
378 #else
379 unsigned len = sizeof *ifp;
380 #endif
381 tif = (struct ifreq *)dmalloc (len, MDL);
382 if (!tif)
383 log_fatal ("no space for ifp.");
384 memcpy (tif, ifp, len);
385 tmp -> ifp = tif;
386 tmp -> primary_address = foo.sin_addr;
389 /* Grab the address... */
390 addr.len = 4;
391 memcpy (addr.iabuf, &foo.sin_addr.s_addr,
392 addr.len);
393 if (dhcp_interface_setup_hook)
394 (*dhcp_interface_setup_hook) (tmp, &addr);
398 /* If we allocated a buffer, free it. */
399 if (ic.ifc_ifcu.ifcu_buf != buf)
400 dfree (ic.ifc_ifcu.ifcu_buf, MDL);
402 #if defined (LINUX_SLASHPROC_DISCOVERY)
403 /* On Linux, interfaces that don't have IP addresses don't
404 show up in the SIOCGIFCONF syscall. This only matters for
405 the DHCP client, of course - the relay agent and server
406 should only care about interfaces that are configured with
407 IP addresses anyway.
409 The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
410 that, when read, prints a human readable network status. We
411 extract the names of the network devices by skipping the first
412 two lines (which are header) and then parsing off everything
413 up to the colon in each subsequent line - these lines start
414 with the interface name, then a colon, then a bunch of
415 statistics. */
417 if (state == DISCOVER_UNCONFIGURED) {
418 FILE *proc_dev;
419 char buffer [256];
420 int skip = 2;
422 proc_dev = fopen (PROCDEV_DEVICE, "r");
423 if (!proc_dev)
424 log_fatal ("%s: %m", PROCDEV_DEVICE);
426 while (fgets (buffer, sizeof buffer, proc_dev)) {
427 char *name = buffer;
428 char *sep;
430 /* Skip the first two blocks, which are header
431 lines. */
432 if (skip) {
433 --skip;
434 continue;
437 sep = strrchr (buffer, ':');
438 if (sep)
439 *sep = '\0';
440 while (*name == ' ')
441 name++;
443 /* See if we've seen an interface that matches
444 this one. */
445 for (tmp = interfaces; tmp; tmp = tmp -> next)
446 if (!strcmp (tmp -> name, name))
447 break;
449 /* If we found one, nothing more to do.. */
450 if (tmp)
451 continue;
453 strncpy (ifr.ifr_name, name, IFNAMSIZ);
455 /* Skip non broadcast interfaces (plus loopback and
456 * point-to-point in case an OS incorrectly marks them
457 * as broadcast).
459 if ((ioctl (sock, SIOCGIFFLAGS, &ifr) < 0) ||
460 (!(ifr.ifr_flags & IFF_BROADCAST)) ||
461 (ifr.ifr_flags & IFF_LOOPBACK ) ||
462 (ifr.ifr_flags & IFF_POINTOPOINT))
463 continue;
465 /* Otherwise, allocate one. */
466 tmp = (struct interface_info *)0;
467 status = interface_allocate (&tmp, MDL);
468 if (status != ISC_R_SUCCESS)
469 log_fatal ("Can't allocate interface %s: %s",
470 name, isc_result_totext (status));
471 tmp -> flags = ir;
472 strncpy (tmp -> name, name, IFNAMSIZ);
473 if (interfaces) {
474 interface_reference (&tmp -> next,
475 interfaces, MDL);
476 interface_dereference (&interfaces, MDL);
478 interface_reference (&interfaces, tmp, MDL);
479 interface_dereference (&tmp, MDL);
480 tmp = interfaces;
482 if (dhcp_interface_discovery_hook)
483 (*dhcp_interface_discovery_hook) (tmp);
486 fclose (proc_dev);
488 #endif
490 /* Now cycle through all the interfaces we found, looking for
491 hardware addresses. */
492 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
493 for (tmp = interfaces; tmp; tmp = tmp -> next) {
494 struct ifreq ifr;
495 struct sockaddr sa;
496 int b, sk;
498 if (!tmp -> ifp) {
499 /* Make up an ifreq structure. */
500 tif = (struct ifreq *)dmalloc (sizeof (struct ifreq),
501 MDL);
502 if (!tif)
503 log_fatal ("no space to remember ifp.");
504 memset (tif, 0, sizeof (struct ifreq));
505 strcpy (tif -> ifr_name, tmp -> name);
506 tmp -> ifp = tif;
509 /* Read the hardware address from this interface. */
510 ifr = *tmp -> ifp;
511 if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
512 continue;
514 sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
516 switch (sa.sa_family) {
517 #ifdef HAVE_ARPHRD_TUNNEL
518 case ARPHRD_TUNNEL:
519 /* ignore tunnel interfaces. */
520 #endif
521 #ifdef HAVE_ARPHRD_ROSE
522 case ARPHRD_ROSE:
523 #endif
524 #ifdef HAVE_ARPHRD_LOOPBACK
525 case ARPHRD_LOOPBACK:
526 /* ignore loopback interface */
527 break;
528 #endif
530 case ARPHRD_ETHER:
531 tmp -> hw_address.hlen = 7;
532 tmp -> hw_address.hbuf [0] = ARPHRD_ETHER;
533 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
534 break;
536 #ifndef HAVE_ARPHRD_IEEE802
537 # define ARPHRD_IEEE802 HTYPE_IEEE802
538 #endif
539 #if defined (HAVE_ARPHRD_IEEE802_TR)
540 case ARPHRD_IEEE802_TR:
541 #endif
542 case ARPHRD_IEEE802:
543 tmp -> hw_address.hlen = 7;
544 tmp -> hw_address.hbuf [0] = ARPHRD_IEEE802;
545 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
546 break;
548 #ifndef HAVE_ARPHRD_FDDI
549 # define ARPHRD_FDDI HTYPE_FDDI
550 #endif
551 case ARPHRD_FDDI:
552 tmp -> hw_address.hlen = 17;
553 tmp -> hw_address.hbuf [0] = HTYPE_FDDI; /* XXX */
554 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 16);
555 break;
557 #ifdef HAVE_ARPHRD_METRICOM
558 case ARPHRD_METRICOM:
559 tmp -> hw_address.hlen = 7;
560 tmp -> hw_address.hbuf [0] = ARPHRD_METRICOM;
561 memcpy (&tmp -> hw_address.hbuf [0], sa.sa_data, 6);
562 break;
563 #endif
565 #ifdef HAVE_ARPHRD_AX25
566 case ARPHRD_AX25:
567 tmp -> hw_address.hlen = 7;
568 tmp -> hw_address.hbuf [0] = ARPHRD_AX25;
569 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
570 break;
571 #endif
573 #ifdef HAVE_ARPHRD_NETROM
574 case ARPHRD_NETROM:
575 tmp -> hw_address.hlen = 7;
576 tmp -> hw_address.hbuf [0] = ARPHRD_NETROM;
577 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
578 break;
579 #endif
581 default:
582 log_error ("%s: unknown hardware address type %d",
583 ifr.ifr_name, sa.sa_family);
584 break;
587 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
589 /* If we're just trying to get a list of interfaces that we might
590 be able to configure, we can quit now. */
591 if (state == DISCOVER_UNCONFIGURED) {
592 close (sock);
593 return;
596 /* Weed out the interfaces that did not have IP addresses. */
597 tmp = last = next = (struct interface_info *)0;
598 if (interfaces)
599 interface_reference (&tmp, interfaces, MDL);
600 while (tmp) {
601 if (next)
602 interface_dereference (&next, MDL);
603 if (tmp -> next)
604 interface_reference (&next, tmp -> next, MDL);
605 /* skip interfaces that are running already */
606 if (tmp -> flags & INTERFACE_RUNNING) {
607 interface_dereference(&tmp, MDL);
608 if(next)
609 interface_reference(&tmp, next, MDL);
610 continue;
612 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
613 state == DISCOVER_REQUESTED)
614 tmp -> flags &= ~(INTERFACE_AUTOMATIC |
615 INTERFACE_REQUESTED);
616 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
617 if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
618 log_fatal ("%s: not found", tmp -> name);
619 if (!last) {
620 if (interfaces)
621 interface_dereference (&interfaces,
622 MDL);
623 if (next)
624 interface_reference (&interfaces, next, MDL);
625 } else {
626 interface_dereference (&last -> next, MDL);
627 if (next)
628 interface_reference (&last -> next,
629 next, MDL);
631 if (tmp -> next)
632 interface_dereference (&tmp -> next, MDL);
634 /* Remember the interface in case we need to know
635 about it later. */
636 if (dummy_interfaces) {
637 interface_reference (&tmp -> next,
638 dummy_interfaces, MDL);
639 interface_dereference (&dummy_interfaces, MDL);
641 interface_reference (&dummy_interfaces, tmp, MDL);
642 interface_dereference (&tmp, MDL);
643 if (next)
644 interface_reference (&tmp, next, MDL);
645 continue;
647 last = tmp;
649 memcpy (&foo, &tmp -> ifp -> ifr_addr,
650 sizeof tmp -> ifp -> ifr_addr);
652 /* We must have a subnet declaration for each interface. */
653 if (!tmp -> shared_network && (state == DISCOVER_SERVER)) {
654 log_error ("%s", "");
655 log_error ("No subnet declaration for %s (%s).",
656 tmp -> name, inet_ntoa (foo.sin_addr));
657 if (supports_multiple_interfaces (tmp)) {
658 log_error ("** Ignoring requests on %s. %s",
659 tmp -> name, "If this is not what");
660 log_error (" you want, please write %s",
661 "a subnet declaration");
662 log_error (" in your dhcpd.conf file %s",
663 "for the network segment");
664 log_error (" to %s %s %s",
665 "which interface",
666 tmp -> name, "is attached. **");
667 log_error ("%s", "");
668 goto next;
669 } else {
670 log_error ("You must write a subnet %s",
671 " declaration for this");
672 log_error ("subnet. You cannot prevent %s",
673 "the DHCP server");
674 log_error ("from listening on this subnet %s",
675 "because your");
676 log_fatal ("operating system does not %s.",
677 "support this capability");
681 /* Find subnets that don't have valid interface
682 addresses... */
683 for (subnet = (tmp -> shared_network
684 ? tmp -> shared_network -> subnets
685 : (struct subnet *)0);
686 subnet; subnet = subnet -> next_sibling) {
687 if (!subnet -> interface_address.len) {
688 /* Set the interface address for this subnet
689 to the first address we found. */
690 subnet -> interface_address.len = 4;
691 memcpy (subnet -> interface_address.iabuf,
692 &foo.sin_addr.s_addr, 4);
696 /* Flag the index as not having been set, so that the
697 interface registerer can set it or not as it chooses. */
698 tmp -> index = -1;
700 /* Register the interface... */
701 if_register_receive (tmp);
702 if_register_send (tmp);
704 interface_stash (tmp);
705 wifcount++;
706 #if defined (HAVE_SETFD)
707 if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0)
708 log_error ("Can't set close-on-exec on %s: %m",
709 tmp -> name);
710 if (tmp -> rfdesc != tmp -> wfdesc) {
711 if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0)
712 log_error ("Can't set close-on-exec on %s: %m",
713 tmp -> name);
715 #endif
716 next:
717 interface_dereference (&tmp, MDL);
718 if (next)
719 interface_reference (&tmp, next, MDL);
722 /* Now register all the remaining interfaces as protocols. */
723 for (tmp = interfaces; tmp; tmp = tmp -> next) {
724 /* not if it's been registered before */
725 if (tmp -> flags & INTERFACE_RUNNING)
726 continue;
727 if (tmp -> rfdesc == -1)
728 continue;
729 status = omapi_register_io_object ((omapi_object_t *)tmp,
730 if_readsocket, 0,
731 got_one, 0, 0);
732 if (status != ISC_R_SUCCESS)
733 log_fatal ("Can't register I/O handle for %s: %s",
734 tmp -> name, isc_result_totext (status));
737 close (sock);
739 if (state == DISCOVER_SERVER && wifcount == 0) {
740 log_info ("%s", "");
741 log_fatal ("Not configured to listen on any interfaces!");
744 if (!setup_fallback) {
745 setup_fallback = 1;
746 maybe_setup_fallback ();
749 #if defined (HAVE_SETFD)
750 if (fallback_interface) {
751 if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
752 log_error ("Can't set close-on-exec on fallback: %m");
753 if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
754 if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
755 log_error ("Can't set close-on-exec on fallback: %m");
758 #endif
761 int if_readsocket (h)
762 omapi_object_t *h;
764 struct interface_info *ip;
766 if (h -> type != dhcp_type_interface)
767 return -1;
768 ip = (struct interface_info *)h;
769 return ip -> rfdesc;
772 int setup_fallback (struct interface_info **fp, const char *file, int line)
774 isc_result_t status;
776 status = interface_allocate (&fallback_interface, file, line);
777 if (status != ISC_R_SUCCESS)
778 log_fatal ("Error allocating fallback interface: %s",
779 isc_result_totext (status));
780 strcpy (fallback_interface -> name, "fallback");
781 if (dhcp_interface_setup_hook)
782 (*dhcp_interface_setup_hook) (fallback_interface,
783 (struct iaddr *)0);
784 status = interface_reference (fp, fallback_interface, file, line);
786 fallback_interface -> index = -1;
787 interface_stash (fallback_interface);
788 return status == ISC_R_SUCCESS;
791 void reinitialize_interfaces ()
793 struct interface_info *ip;
795 for (ip = interfaces; ip; ip = ip -> next) {
796 if_reinitialize_receive (ip);
797 if_reinitialize_send (ip);
800 if (fallback_interface)
801 if_reinitialize_send (fallback_interface);
803 interfaces_invalidated = 1;
806 isc_result_t got_one (h)
807 omapi_object_t *h;
809 struct sockaddr_in from;
810 struct hardware hfrom;
811 struct iaddr ifrom;
812 int result;
813 union {
814 unsigned char packbuf [4095]; /* Packet input buffer.
815 Must be as large as largest
816 possible MTU. */
817 struct dhcp_packet packet;
818 } u;
819 struct interface_info *ip;
821 if (h -> type != dhcp_type_interface)
822 return ISC_R_INVALIDARG;
823 ip = (struct interface_info *)h;
825 again:
826 if ((result =
827 receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
828 log_error ("receive_packet failed on %s: %m", ip -> name);
829 return ISC_R_UNEXPECTED;
831 if (result == 0)
832 return ISC_R_UNEXPECTED;
834 if (bootp_packet_handler) {
835 ifrom.len = 4;
836 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
838 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
839 from.sin_port, ifrom, &hfrom);
842 /* If there is buffered data, read again. This is for, e.g.,
843 bpf, which may return two packets at once. */
844 if (ip -> rbuf_offset != ip -> rbuf_len)
845 goto again;
846 return ISC_R_SUCCESS;
849 #if !defined (SMALL)
850 isc_result_t dhcp_interface_set_value (omapi_object_t *h,
851 omapi_object_t *id,
852 omapi_data_string_t *name,
853 omapi_typed_data_t *value)
855 struct interface_info *interface;
856 isc_result_t status;
858 if (h -> type != dhcp_type_interface)
859 return ISC_R_INVALIDARG;
860 interface = (struct interface_info *)h;
862 if (!omapi_ds_strcmp (name, "name")) {
863 if ((value -> type == omapi_datatype_data ||
864 value -> type == omapi_datatype_string) &&
865 value -> u.buffer.len < sizeof interface -> name) {
866 memcpy (interface -> name,
867 value -> u.buffer.value,
868 value -> u.buffer.len);
869 interface -> name [value -> u.buffer.len] = 0;
870 } else
871 return ISC_R_INVALIDARG;
872 return ISC_R_SUCCESS;
875 /* Try to find some inner object that can take the value. */
876 if (h -> inner && h -> inner -> type -> set_value) {
877 status = ((*(h -> inner -> type -> set_value))
878 (h -> inner, id, name, value));
879 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
880 return status;
883 return ISC_R_NOTFOUND;
887 isc_result_t dhcp_interface_get_value (omapi_object_t *h,
888 omapi_object_t *id,
889 omapi_data_string_t *name,
890 omapi_value_t **value)
892 return ISC_R_NOTIMPLEMENTED;
895 isc_result_t dhcp_interface_destroy (omapi_object_t *h,
896 const char *file, int line)
898 struct interface_info *interface;
900 if (h -> type != dhcp_type_interface)
901 return ISC_R_INVALIDARG;
902 interface = (struct interface_info *)h;
904 if (interface -> ifp) {
905 dfree (interface -> ifp, file, line);
906 interface -> ifp = 0;
908 if (interface -> next)
909 interface_dereference (&interface -> next, file, line);
910 if (interface -> rbuf) {
911 dfree (interface -> rbuf, file, line);
912 interface -> rbuf = (unsigned char *)0;
914 if (interface -> client)
915 interface -> client = (struct client_state *)0;
917 if (interface -> shared_network)
918 omapi_object_dereference ((omapi_object_t **)
919 &interface -> shared_network, MDL);
921 return ISC_R_SUCCESS;
924 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
925 const char *name, va_list ap)
927 struct interface_info *ip, *interface;
928 isc_result_t status;
930 if (h -> type != dhcp_type_interface)
931 return ISC_R_INVALIDARG;
932 interface = (struct interface_info *)h;
934 /* If it's an update signal, see if the interface is dead right
935 now, or isn't known at all, and if that's the case, revive it. */
936 if (!strcmp (name, "update")) {
937 for (ip = dummy_interfaces; ip; ip = ip -> next)
938 if (ip == interface)
939 break;
940 if (ip && dhcp_interface_startup_hook)
941 return (*dhcp_interface_startup_hook) (ip);
943 for (ip = interfaces; ip; ip = ip -> next)
944 if (ip == interface)
945 break;
946 if (!ip && dhcp_interface_startup_hook)
947 return (*dhcp_interface_startup_hook) (ip);
950 /* Try to find some inner object that can take the value. */
951 if (h -> inner && h -> inner -> type -> get_value) {
952 status = ((*(h -> inner -> type -> signal_handler))
953 (h -> inner, name, ap));
954 if (status == ISC_R_SUCCESS)
955 return status;
957 return ISC_R_NOTFOUND;
960 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
961 omapi_object_t *id,
962 omapi_object_t *h)
964 struct interface_info *interface;
965 isc_result_t status;
967 if (h -> type != dhcp_type_interface)
968 return ISC_R_INVALIDARG;
969 interface = (struct interface_info *)h;
971 /* Write out all the values. */
973 status = omapi_connection_put_name (c, "state");
974 if (status != ISC_R_SUCCESS)
975 return status;
976 if (interface -> flags && INTERFACE_REQUESTED)
977 status = omapi_connection_put_string (c, "up");
978 else
979 status = omapi_connection_put_string (c, "down");
980 if (status != ISC_R_SUCCESS)
981 return status;
983 /* Write out the inner object, if any. */
984 if (h -> inner && h -> inner -> type -> stuff_values) {
985 status = ((*(h -> inner -> type -> stuff_values))
986 (c, id, h -> inner));
987 if (status == ISC_R_SUCCESS)
988 return status;
991 return ISC_R_SUCCESS;
994 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
995 omapi_object_t *id,
996 omapi_object_t *ref)
998 omapi_value_t *tv = (omapi_value_t *)0;
999 isc_result_t status;
1000 struct interface_info *interface;
1002 if (!ref)
1003 return ISC_R_NOKEYS;
1005 /* First see if we were sent a handle. */
1006 status = omapi_get_value_str (ref, id, "handle", &tv);
1007 if (status == ISC_R_SUCCESS) {
1008 status = omapi_handle_td_lookup (ip, tv -> value);
1010 omapi_value_dereference (&tv, MDL);
1011 if (status != ISC_R_SUCCESS)
1012 return status;
1014 /* Don't return the object if the type is wrong. */
1015 if ((*ip) -> type != dhcp_type_interface) {
1016 omapi_object_dereference (ip, MDL);
1017 return ISC_R_INVALIDARG;
1021 /* Now look for an interface name. */
1022 status = omapi_get_value_str (ref, id, "name", &tv);
1023 if (status == ISC_R_SUCCESS) {
1024 char *s;
1025 unsigned len;
1026 for (interface = interfaces; interface;
1027 interface = interface -> next) {
1028 s = memchr (interface -> name, 0, IFNAMSIZ);
1029 if (s)
1030 len = s - &interface -> name [0];
1031 else
1032 len = IFNAMSIZ;
1033 if ((tv -> value -> u.buffer.len == len &&
1034 !memcmp (interface -> name,
1035 (char *)tv -> value -> u.buffer.value,
1036 len)))
1037 break;
1039 if (!interface) {
1040 for (interface = dummy_interfaces;
1041 interface; interface = interface -> next) {
1042 s = memchr (interface -> name, 0, IFNAMSIZ);
1043 if (s)
1044 len = s - &interface -> name [0];
1045 else
1046 len = IFNAMSIZ;
1047 if ((tv -> value -> u.buffer.len == len &&
1048 !memcmp (interface -> name,
1049 (char *)
1050 tv -> value -> u.buffer.value,
1051 len)))
1052 break;
1056 omapi_value_dereference (&tv, MDL);
1057 if (*ip && *ip != (omapi_object_t *)interface) {
1058 omapi_object_dereference (ip, MDL);
1059 return ISC_R_KEYCONFLICT;
1060 } else if (!interface) {
1061 if (*ip)
1062 omapi_object_dereference (ip, MDL);
1063 return ISC_R_NOTFOUND;
1064 } else if (!*ip)
1065 omapi_object_reference (ip,
1066 (omapi_object_t *)interface,
1067 MDL);
1070 /* If we get to here without finding an interface, no valid key was
1071 specified. */
1072 if (!*ip)
1073 return ISC_R_NOKEYS;
1074 return ISC_R_SUCCESS;
1077 /* actually just go discover the interface */
1078 isc_result_t dhcp_interface_create (omapi_object_t **lp,
1079 omapi_object_t *id)
1081 struct interface_info *hp;
1082 isc_result_t status;
1084 hp = (struct interface_info *)0;
1085 status = interface_allocate (&hp, MDL);
1086 if (status != ISC_R_SUCCESS)
1087 return status;
1088 hp -> flags = INTERFACE_REQUESTED;
1089 status = interface_reference ((struct interface_info **)lp, hp, MDL);
1090 interface_dereference (&hp, MDL);
1091 return status;
1093 #endif
1095 isc_result_t dhcp_interface_remove (omapi_object_t *lp,
1096 omapi_object_t *id)
1098 struct interface_info *interface, *ip, *last;
1100 interface = (struct interface_info *)lp;
1102 /* remove from interfaces */
1103 last = 0;
1104 for (ip = interfaces; ip; ip = ip -> next) {
1105 if (ip == interface) {
1106 if (last) {
1107 interface_dereference (&last -> next, MDL);
1108 if (ip -> next)
1109 interface_reference (&last -> next,
1110 ip -> next, MDL);
1111 } else {
1112 interface_dereference (&interfaces, MDL);
1113 if (ip -> next)
1114 interface_reference (&interfaces,
1115 ip -> next, MDL);
1117 if (ip -> next)
1118 interface_dereference (&ip -> next, MDL);
1119 break;
1121 last = ip;
1123 if (!ip)
1124 return ISC_R_NOTFOUND;
1126 /* add the interface to the dummy_interface list */
1127 if (dummy_interfaces) {
1128 interface_reference (&interface -> next,
1129 dummy_interfaces, MDL);
1130 interface_dereference (&dummy_interfaces, MDL);
1132 interface_reference (&dummy_interfaces, interface, MDL);
1134 /* do a DHCPRELEASE */
1135 if (dhcp_interface_shutdown_hook)
1136 (*dhcp_interface_shutdown_hook) (interface);
1138 /* remove the io object */
1139 omapi_unregister_io_object ((omapi_object_t *)interface);
1141 if_deregister_send (interface);
1142 if_deregister_receive (interface);
1144 return ISC_R_SUCCESS;
1147 void interface_stash (struct interface_info *tptr)
1149 struct interface_info **vec;
1150 int delta;
1152 /* If the registerer didn't assign an index, assign one now. */
1153 if (tptr -> index == -1) {
1154 tptr -> index = interface_count++;
1155 while (tptr -> index < interface_max &&
1156 interface_vector [tptr -> index])
1157 tptr -> index = interface_count++;
1160 if (interface_max <= tptr -> index) {
1161 delta = tptr -> index - interface_max + 10;
1162 vec = dmalloc ((interface_max + delta) *
1163 sizeof (struct interface_info *), MDL);
1164 if (!vec)
1165 return;
1166 memset (&vec [interface_max], 0,
1167 (sizeof (struct interface_info *)) * delta);
1168 interface_max += delta;
1169 if (interface_vector) {
1170 memcpy (vec, interface_vector,
1171 (interface_count *
1172 sizeof (struct interface_info *)));
1173 dfree (interface_vector, MDL);
1175 interface_vector = vec;
1177 interface_reference (&interface_vector [tptr -> index], tptr, MDL);
1178 if (tptr -> index >= interface_count)
1179 interface_count = tptr -> index + 1;
1180 #if defined (TRACING)
1181 trace_interface_register (interface_trace, tptr);
1182 #endif
1185 void interface_snorf (struct interface_info *tmp, int ir)
1187 tmp -> circuit_id = (u_int8_t *)tmp -> name;
1188 tmp -> circuit_id_len = strlen (tmp -> name);
1189 tmp -> remote_id = 0;
1190 tmp -> remote_id_len = 0;
1191 tmp -> flags = ir;
1192 if (interfaces) {
1193 interface_reference (&tmp -> next,
1194 interfaces, MDL);
1195 interface_dereference (&interfaces, MDL);
1197 interface_reference (&interfaces, tmp, MDL);