Pre-2.0 release, MFC firewire disk changes to properly detach SIMs.
[dragonfly.git] / contrib / dhcp-3.0 / common / discover.c
blobc2f9d47daacb8f3faca8a6fc335f7baedc694137
1 /* dispatch.c
3 Network input dispatcher... */
5 /*
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.
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.42.2.15 2004/06/10 17:59:16 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n";
38 #endif /* not lint */
40 #include "dhcpd.h"
41 #include <sys/ioctl.h>
43 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
44 int interfaces_invalidated;
45 int quiet_interface_discovery;
46 u_int16_t local_port;
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,
58 unsigned int,
59 struct iaddr, struct hardware *));
61 omapi_object_type_t *dhcp_type_interface;
62 #if defined (TRACING)
63 trace_type_t *interface_trace;
64 trace_type_t *inpacket_trace;
65 trace_type_t *outpacket_trace;
66 #endif
67 struct interface_info **interface_vector;
68 int interface_count;
69 int interface_max;
71 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
73 isc_result_t interface_setup ()
75 isc_result_t status;
76 status = omapi_object_type_register (&dhcp_type_interface,
77 "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,
86 0, 0, 0,
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));
93 return status;
96 #if defined (TRACING)
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);
109 #endif
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)
125 int state;
127 struct interface_info *tmp, *ip;
128 struct interface_info *last, *next;
129 char buf [2048];
130 struct ifconf ic;
131 struct ifreq ifr;
132 int i;
133 int sock;
134 int address_count = 0;
135 struct subnet *subnet;
136 struct shared_network *share;
137 struct sockaddr_in foo;
138 int ir;
139 struct ifreq *tif;
140 #ifdef ALIAS_NAMES_PERMUTED
141 char *s;
142 #endif
143 isc_result_t status;
144 static int setup_fallback = 0;
145 int wifcount = 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. */
162 ic.ifc_len = 0;
163 ic.ifc_ifcu.ifcu_buf = (caddr_t)NULL;
164 #else
165 /* otherwise, we just feed it a starting size, and it'll tell us if
166 * it needs more */
168 ic.ifc_len = sizeof buf;
169 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
170 #endif
172 gifconf_again:
173 i = ioctl(sock, SIOCGIFCONF, &ic);
175 if (i < 0)
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;
183 goto gifconf_again;
185 #endif
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
192 #endif
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.");
197 goto gifconf_again;
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;
202 goto gifconf_again;
203 #endif
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))
212 ir = 0;
213 else if (state == DISCOVER_UNCONFIGURED)
214 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
215 else
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);
221 #ifdef HAVE_SA_LEN
222 if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr))
223 i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
224 else
225 #endif
226 i += sizeof *ifp;
228 #ifdef ALIAS_NAMES_PERMUTED
229 if ((s = strrchr (ifp -> ifr_name, ':'))) {
230 *s = 0;
232 #endif
234 #ifdef SKIP_DUMMY_INTERFACES
235 if (!strncmp (ifp -> ifr_name, "dummy", 5))
236 continue;
237 #endif
240 /* See if this is the sort of interface we want to
241 deal with. */
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",
245 ifr.ifr_name);
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))
250 break;
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))
261 continue;
263 /* If there isn't already an interface by this name,
264 allocate one. */
265 if (!tmp) {
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",
270 ifp -> ifr_name,
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. */
283 #ifdef HAVE_AF_LINK
284 if (ifp -> ifr_addr.sa_family == AF_LINK) {
285 struct sockaddr_dl *foo = ((struct sockaddr_dl *)
286 (&ifp -> ifr_addr));
287 #if defined (HAVE_SIN_LEN)
288 tmp -> hw_address.hlen = foo -> sdl_alen;
289 #else
290 tmp -> hw_address.hlen = 6; /* XXX!!! */
291 #endif
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. */
296 } else
297 #endif /* AF_LINK */
299 if (ifp -> ifr_addr.sa_family == AF_INET) {
300 struct iaddr addr;
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))
310 continue;
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. */
316 if (!tmp -> ifp) {
317 #ifdef HAVE_SA_LEN
318 unsigned len = ((sizeof ifp -> ifr_name) +
319 ifp -> ifr_addr.sa_len);
320 #else
321 unsigned len = sizeof *ifp;
322 #endif
323 tif = (struct ifreq *)dmalloc (len, MDL);
324 if (!tif)
325 log_fatal ("no space for ifp.");
326 memcpy (tif, ifp, len);
327 tmp -> ifp = tif;
328 tmp -> primary_address = foo.sin_addr;
331 /* Grab the address... */
332 addr.len = 4;
333 memcpy (addr.iabuf, &foo.sin_addr.s_addr,
334 addr.len);
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
349 IP addresses anyway.
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
357 statistics. */
359 if (state == DISCOVER_UNCONFIGURED) {
360 FILE *proc_dev;
361 char buffer [256];
362 int skip = 2;
364 proc_dev = fopen (PROCDEV_DEVICE, "r");
365 if (!proc_dev)
366 log_fatal ("%s: %m", PROCDEV_DEVICE);
368 while (fgets (buffer, sizeof buffer, proc_dev)) {
369 char *name = buffer;
370 char *sep;
372 /* Skip the first two blocks, which are header
373 lines. */
374 if (skip) {
375 --skip;
376 continue;
379 sep = strrchr (buffer, ':');
380 if (sep)
381 *sep = '\0';
382 while (*name == ' ')
383 name++;
385 /* See if we've seen an interface that matches
386 this one. */
387 for (tmp = interfaces; tmp; tmp = tmp -> next)
388 if (!strcmp (tmp -> name, name))
389 break;
391 /* If we found one, nothing more to do.. */
392 if (tmp)
393 continue;
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));
401 tmp -> flags = ir;
402 strncpy (tmp -> name, name, IFNAMSIZ);
403 if (interfaces) {
404 interface_reference (&tmp -> next,
405 interfaces, MDL);
406 interface_dereference (&interfaces, MDL);
408 interface_reference (&interfaces, tmp, MDL);
409 interface_dereference (&tmp, MDL);
410 tmp = interfaces;
412 if (dhcp_interface_discovery_hook)
413 (*dhcp_interface_discovery_hook) (tmp);
416 fclose (proc_dev);
418 #endif
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) {
424 struct ifreq ifr;
425 struct sockaddr sa;
426 int b, sk;
428 if (!tmp -> ifp) {
429 /* Make up an ifreq structure. */
430 tif = (struct ifreq *)dmalloc (sizeof (struct ifreq),
431 MDL);
432 if (!tif)
433 log_fatal ("no space to remember ifp.");
434 memset (tif, 0, sizeof (struct ifreq));
435 strcpy (tif -> ifr_name, tmp -> name);
436 tmp -> ifp = tif;
439 /* Read the hardware address from this interface. */
440 ifr = *tmp -> ifp;
441 if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
442 continue;
444 sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
446 switch (sa.sa_family) {
447 #ifdef HAVE_ARPHRD_TUNNEL
448 case ARPHRD_TUNNEL:
449 /* ignore tunnel interfaces. */
450 #endif
451 #ifdef HAVE_ARPHRD_ROSE
452 case ARPHRD_ROSE:
453 #endif
454 #ifdef HAVE_ARPHRD_LOOPBACK
455 case ARPHRD_LOOPBACK:
456 /* ignore loopback interface */
457 break;
458 #endif
460 case ARPHRD_ETHER:
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);
464 break;
466 #ifndef HAVE_ARPHRD_IEEE802
467 # define ARPHRD_IEEE802 HTYPE_IEEE802
468 #endif
469 #if defined (HAVE_ARPHRD_IEEE802_TR)
470 case ARPHRD_IEEE802_TR:
471 #endif
472 case ARPHRD_IEEE802:
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);
476 break;
478 #ifndef HAVE_ARPHRD_FDDI
479 # define ARPHRD_FDDI HTYPE_FDDI
480 #endif
481 case ARPHRD_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);
485 break;
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);
492 break;
493 #endif
495 #ifdef HAVE_ARPHRD_AX25
496 case 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);
500 break;
501 #endif
503 #ifdef HAVE_ARPHRD_NETROM
504 case 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);
508 break;
509 #endif
511 default:
512 log_error ("%s: unknown hardware address type %d",
513 ifr.ifr_name, sa.sa_family);
514 break;
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) {
522 close (sock);
523 return;
526 /* Weed out the interfaces that did not have IP addresses. */
527 tmp = last = next = (struct interface_info *)0;
528 if (interfaces)
529 interface_reference (&tmp, interfaces, MDL);
530 while (tmp) {
531 if (next)
532 interface_dereference (&next, MDL);
533 if (tmp -> next)
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);
538 if(next)
539 interface_reference(&tmp, next, MDL);
540 continue;
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);
549 if (!last) {
550 if (interfaces)
551 interface_dereference (&interfaces,
552 MDL);
553 if (next)
554 interface_reference (&interfaces, next, MDL);
555 } else {
556 interface_dereference (&last -> next, MDL);
557 if (next)
558 interface_reference (&last -> next,
559 next, MDL);
561 if (tmp -> next)
562 interface_dereference (&tmp -> next, MDL);
564 /* Remember the interface in case we need to know
565 about it later. */
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);
573 if (next)
574 interface_reference (&tmp, next, MDL);
575 continue;
577 last = tmp;
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",
595 "which interface",
596 tmp -> name, "is attached. **");
597 log_error ("%s", "");
598 goto next;
599 } else {
600 log_error ("You must write a subnet %s",
601 " declaration for this");
602 log_error ("subnet. You cannot prevent %s",
603 "the DHCP server");
604 log_error ("from listening on this subnet %s",
605 "because your");
606 log_fatal ("operating system does not %s.",
607 "support this capability");
611 /* Find subnets that don't have valid interface
612 addresses... */
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. */
628 tmp -> index = -1;
630 /* Register the interface... */
631 if_register_receive (tmp);
632 if_register_send (tmp);
634 interface_stash (tmp);
635 wifcount++;
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",
639 tmp -> name);
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",
643 tmp -> name);
645 #endif
646 next:
647 interface_dereference (&tmp, MDL);
648 if (next)
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)
656 continue;
657 if (tmp -> rfdesc == -1)
658 continue;
659 status = omapi_register_io_object ((omapi_object_t *)tmp,
660 if_readsocket, 0,
661 got_one, 0, 0);
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));
667 close (sock);
669 if (state == DISCOVER_SERVER && wifcount == 0) {
670 log_info ("%s", "");
671 log_fatal ("Not configured to listen on any interfaces!");
674 if (!setup_fallback) {
675 setup_fallback = 1;
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");
688 #endif
691 int if_readsocket (h)
692 omapi_object_t *h;
694 struct interface_info *ip;
696 if (h -> type != dhcp_type_interface)
697 return -1;
698 ip = (struct interface_info *)h;
699 return ip -> rfdesc;
702 int setup_fallback (struct interface_info **fp, const char *file, int line)
704 isc_result_t status;
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,
713 (struct iaddr *)0);
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)
737 omapi_object_t *h;
739 struct sockaddr_in from;
740 struct hardware hfrom;
741 struct iaddr ifrom;
742 int result;
743 union {
744 unsigned char packbuf [4095]; /* Packet input buffer.
745 Must be as large as largest
746 possible MTU. */
747 struct dhcp_packet packet;
748 } u;
749 struct interface_info *ip;
751 if (h -> type != dhcp_type_interface)
752 return ISC_R_INVALIDARG;
753 ip = (struct interface_info *)h;
755 again:
756 if ((result =
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;
761 if (result == 0)
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) {
773 ifrom.len = 4;
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)
783 goto again;
784 return ISC_R_SUCCESS;
787 isc_result_t dhcp_interface_set_value (omapi_object_t *h,
788 omapi_object_t *id,
789 omapi_data_string_t *name,
790 omapi_typed_data_t *value)
792 struct interface_info *interface;
793 isc_result_t status;
794 int foo;
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;
808 } else
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)
818 return status;
821 return ISC_R_NOTFOUND;
825 isc_result_t dhcp_interface_get_value (omapi_object_t *h,
826 omapi_object_t *id,
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;
837 isc_result_t status;
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;
869 isc_result_t status;
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)
879 if (ip == interface)
880 break;
881 if (ip && dhcp_interface_startup_hook)
882 return (*dhcp_interface_startup_hook) (ip);
884 for (ip = interfaces; ip; ip = ip -> next)
885 if (ip == interface)
886 break;
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)
896 return status;
898 return ISC_R_NOTFOUND;
901 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
902 omapi_object_t *id,
903 omapi_object_t *h)
905 struct interface_info *interface;
906 isc_result_t status;
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)
916 return status;
917 if (interface -> flags && INTERFACE_REQUESTED)
918 status = omapi_connection_put_string (c, "up");
919 else
920 status = omapi_connection_put_string (c, "down");
921 if (status != ISC_R_SUCCESS)
922 return status;
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)
929 return status;
932 return ISC_R_SUCCESS;
935 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
936 omapi_object_t *id,
937 omapi_object_t *ref)
939 omapi_value_t *tv = (omapi_value_t *)0;
940 isc_result_t status;
941 struct interface_info *interface;
943 if (!ref)
944 return ISC_R_NOKEYS;
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)
953 return status;
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) {
965 char *s;
966 unsigned len;
967 for (interface = interfaces; interface;
968 interface = interface -> next) {
969 s = memchr (interface -> name, 0, IFNAMSIZ);
970 if (s)
971 len = s - &interface -> name [0];
972 else
973 len = IFNAMSIZ;
974 if ((tv -> value -> u.buffer.len == len &&
975 !memcmp (interface -> name,
976 (char *)tv -> value -> u.buffer.value,
977 len)))
978 break;
980 if (!interface) {
981 for (interface = dummy_interfaces;
982 interface; interface = interface -> next) {
983 s = memchr (interface -> name, 0, IFNAMSIZ);
984 if (s)
985 len = s - &interface -> name [0];
986 else
987 len = IFNAMSIZ;
988 if ((tv -> value -> u.buffer.len == len &&
989 !memcmp (interface -> name,
990 (char *)
991 tv -> value -> u.buffer.value,
992 len)))
993 break;
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) {
1002 if (*ip)
1003 omapi_object_dereference (ip, MDL);
1004 return ISC_R_NOTFOUND;
1005 } else if (!*ip)
1006 omapi_object_reference (ip,
1007 (omapi_object_t *)interface,
1008 MDL);
1011 /* If we get to here without finding an interface, no valid key was
1012 specified. */
1013 if (!*ip)
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,
1020 omapi_object_t *id)
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)
1028 return status;
1029 hp -> flags = INTERFACE_REQUESTED;
1030 status = interface_reference ((struct interface_info **)lp, hp, MDL);
1031 interface_dereference (&hp, MDL);
1032 return status;
1035 isc_result_t dhcp_interface_remove (omapi_object_t *lp,
1036 omapi_object_t *id)
1038 struct interface_info *interface, *ip, *last;
1040 interface = (struct interface_info *)lp;
1042 /* remove from interfaces */
1043 last = 0;
1044 for (ip = interfaces; ip; ip = ip -> next) {
1045 if (ip == interface) {
1046 if (last) {
1047 interface_dereference (&last -> next, MDL);
1048 if (ip -> next)
1049 interface_reference (&last -> next,
1050 ip -> next, MDL);
1051 } else {
1052 interface_dereference (&interfaces, MDL);
1053 if (ip -> next)
1054 interface_reference (&interfaces,
1055 ip -> next, MDL);
1057 if (ip -> next)
1058 interface_dereference (&ip -> next, MDL);
1059 break;
1061 last = ip;
1063 if (!ip)
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;
1090 int delta;
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);
1104 if (!vec)
1105 return;
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,
1111 (interface_count *
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);
1122 #endif
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;
1131 tmp -> flags = ir;
1132 if (interfaces) {
1133 interface_reference (&tmp -> next,
1134 interfaces, MDL);
1135 interface_dereference (&interfaces, MDL);
1137 interface_reference (&interfaces, tmp, MDL);