tools/adflib: build only host variant which is used by Sam440 target
[AROS.git] / workbench / network / stacks / AROSTCP / dhcp / common / discover.c
blob0793d2abe598c9091647b6c8797ff64d93c40baa
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 #if 0
36 static char copyright[] =
37 "$Id$ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n";
38 #endif
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;
128 // struct interface_info *ip;
129 struct interface_info *last, *next;
130 char buf [2048];
131 struct ifconf ic;
132 struct ifreq ifr;
133 int i;
134 int sock;
135 // int address_count = 0;
136 struct subnet *subnet;
137 // struct shared_network *share;
138 struct sockaddr_in foo;
139 int ir;
140 struct ifreq *tif;
141 #ifdef ALIAS_NAMES_PERMUTED
142 char *s;
143 #endif
144 isc_result_t status;
145 static int setup_fallback = 0;
146 int wifcount = 0;
148 /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
149 if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
150 log_fatal ("Can't create addrlist socket");
152 /* Get the interface configuration information... */
154 #ifdef SIOCGIFCONF_ZERO_PROBE
155 /* linux will only tell us how long a buffer it wants if we give it
156 * a null buffer first. So, do a dry run to figure out the length.
158 * XXX this code is duplicated from below because trying to fold
159 * the logic into the if statement and goto resulted in excesssive
160 * obfuscation. The intent is that unless you run Linux you shouldn't
161 * have to deal with this. */
163 ic.ifc_len = 0;
164 ic.ifc_ifcu.ifcu_buf = (caddr_t)NULL;
165 #else
166 /* otherwise, we just feed it a starting size, and it'll tell us if
167 * it needs more */
169 ic.ifc_len = sizeof buf;
170 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
171 #endif
173 gifconf_again:
174 #ifdef SOCKET_IS_NOT_A_FILE
175 i = IoctlSocket(sock, SIOCGIFCONF, (char *)&ic);
176 #else
177 i = ioctl(sock, SIOCGIFCONF, &ic);
178 #endif
180 if (i < 0)
181 log_fatal ("ioctl: SIOCGIFCONF: %m");
183 #ifdef SIOCGIFCONF_ZERO_PROBE
184 /* Workaround for SIOCGIFCONF bug on some Linux versions. */
185 if (ic.ifc_ifcu.ifcu_buf == 0 && ic.ifc_len == 0) {
186 ic.ifc_len = sizeof buf;
187 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
188 goto gifconf_again;
190 #endif
192 /* If the SIOCGIFCONF resulted in more data than would fit in
193 a buffer, allocate a bigger buffer. */
194 if ((ic.ifc_ifcu.ifcu_buf == buf
195 #ifdef SIOCGIFCONF_ZERO_PROBE
196 || ic.ifc_ifcu.ifcu_buf == 0
197 #endif
198 ) && ic.ifc_len > sizeof buf) {
199 ic.ifc_ifcu.ifcu_buf = dmalloc ((size_t)ic.ifc_len, MDL);
200 if (!ic.ifc_ifcu.ifcu_buf)
201 log_fatal ("Can't allocate SIOCGIFCONF buffer.");
202 goto gifconf_again;
203 #ifdef SIOCGIFCONF_ZERO_PROBE
204 } else if (ic.ifc_ifcu.ifcu_buf == 0) {
205 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
206 ic.ifc_len = sizeof buf;
207 goto gifconf_again;
208 #endif
212 /* If we already have a list of interfaces, and we're running as
213 a DHCP server, the interfaces were requested. */
214 if (interfaces && (state == DISCOVER_SERVER ||
215 state == DISCOVER_RELAY ||
216 state == DISCOVER_REQUESTED))
217 ir = 0;
218 else if (state == DISCOVER_UNCONFIGURED)
219 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
220 else
221 ir = INTERFACE_REQUESTED;
223 /* Cycle through the list of interfaces looking for IP addresses. */
224 for (i = 0; i < ic.ifc_len;) {
225 struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
226 #ifdef HAVE_SA_LEN
227 if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr))
228 i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
229 else
230 #endif
231 i += sizeof *ifp;
233 #ifdef ALIAS_NAMES_PERMUTED
234 if ((s = strrchr (ifp -> ifr_name, ':'))) {
235 *s = 0;
237 #endif
239 #ifdef SKIP_DUMMY_INTERFACES
240 if (!strncmp (ifp -> ifr_name, "dummy", 5))
241 continue;
242 #endif
245 /* See if this is the sort of interface we want to
246 deal with. */
247 strcpy (ifr.ifr_name, ifp -> ifr_name);
248 #ifdef SOCKET_IS_NOT_A_FILE
249 if (IoctlSocket (sock, SIOCGIFFLAGS, (char *)&ifr) < 0)
250 #else
251 if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
252 #endif
253 log_fatal ("Can't get interface flags for %s: %m",
254 ifr.ifr_name);
256 /* See if we've seen an interface that matches this one. */
257 for (tmp = interfaces; tmp; tmp = tmp -> next)
258 if (!strcmp (tmp -> name, ifp -> ifr_name))
259 break;
261 /* Skip non broadcast interfaces (plus loopback and
262 point-to-point in case an OS incorrectly marks them
263 as broadcast). Also skip down interfaces unless we're
264 trying to get a list of configurable interfaces. */
265 if (((!(ifr.ifr_flags & IFF_BROADCAST) ||
266 ifr.ifr_flags & IFF_LOOPBACK ||
267 ifr.ifr_flags & IFF_POINTOPOINT) && !tmp) ||
268 (!(ifr.ifr_flags & IFF_UP) &&
269 state != DISCOVER_UNCONFIGURED))
270 continue;
272 /* If there isn't already an interface by this name,
273 allocate one. */
274 if (!tmp) {
275 tmp = (struct interface_info *)0;
276 status = interface_allocate (&tmp, MDL);
277 if (status != ISC_R_SUCCESS)
278 log_fatal ("Error allocating interface %s: %s",
279 ifp -> ifr_name,
280 isc_result_totext (status));
281 strcpy (tmp -> name, ifp -> ifr_name);
282 interface_snorf (tmp, ir);
283 interface_dereference (&tmp, MDL);
284 tmp = interfaces; /* XXX */
287 if (dhcp_interface_discovery_hook)
288 (*dhcp_interface_discovery_hook) (tmp);
290 /* If we have the capability, extract link information
291 and record it in a linked list. */
292 #ifdef HAVE_AF_LINK
293 if (ifp -> ifr_addr.sa_family == AF_LINK) {
294 struct sockaddr_dl *foo = ((struct sockaddr_dl *)
295 (&ifp -> ifr_addr));
296 #if defined (HAVE_SIN_LEN)
297 tmp -> hw_address.hlen = foo -> sdl_alen;
298 #else
299 tmp -> hw_address.hlen = 6; /* XXX!!! */
300 #endif
301 tmp -> hw_address.hbuf [0] = HTYPE_ETHER; /* XXX */
302 memcpy (&tmp -> hw_address.hbuf [1],
303 LLADDR (foo), tmp -> hw_address.hlen);
304 tmp -> hw_address.hlen++; /* for type. */
305 } else
306 #endif /* AF_LINK */
308 if (ifp -> ifr_addr.sa_family == AF_INET) {
309 struct iaddr addr;
311 /* Get a pointer to the address... */
312 memcpy (&foo, &ifp -> ifr_addr,
313 sizeof ifp -> ifr_addr);
315 /* We don't want the loopback interface. */
316 if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK) &&
317 ((tmp -> flags & INTERFACE_AUTOMATIC) &&
318 state == DISCOVER_SERVER))
319 continue;
322 /* If this is the first real IP address we've
323 found, keep a pointer to ifreq structure in
324 which we found it. */
325 if (!tmp -> ifp) {
326 #ifdef HAVE_SA_LEN
327 unsigned len = ((sizeof ifp -> ifr_name) +
328 ifp -> ifr_addr.sa_len);
329 #else
330 unsigned len = sizeof *ifp;
331 #endif
332 tif = (struct ifreq *)dmalloc (len, MDL);
333 if (!tif)
334 log_fatal ("no space for ifp.");
335 memcpy (tif, ifp, len);
336 tmp -> ifp = tif;
337 tmp -> primary_address = foo.sin_addr;
340 /* Grab the address... */
341 addr.len = 4;
342 memcpy (addr.iabuf, &foo.sin_addr.s_addr,
343 addr.len);
344 if (dhcp_interface_setup_hook)
345 (*dhcp_interface_setup_hook) (tmp, &addr);
349 /* If we allocated a buffer, free it. */
350 if (ic.ifc_ifcu.ifcu_buf != buf)
351 dfree (ic.ifc_ifcu.ifcu_buf, MDL);
353 #if defined (LINUX_SLASHPROC_DISCOVERY)
354 /* On Linux, interfaces that don't have IP addresses don't
355 show up in the SIOCGIFCONF syscall. This only matters for
356 the DHCP client, of course - the relay agent and server
357 should only care about interfaces that are configured with
358 IP addresses anyway.
360 The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
361 that, when read, prints a human readable network status. We
362 extract the names of the network devices by skipping the first
363 two lines (which are header) and then parsing off everything
364 up to the colon in each subsequent line - these lines start
365 with the interface name, then a colon, then a bunch of
366 statistics. */
368 if (state == DISCOVER_UNCONFIGURED) {
369 FILE *proc_dev;
370 char buffer [256];
371 int skip = 2;
373 proc_dev = fopen (PROCDEV_DEVICE, "r");
374 if (!proc_dev)
375 log_fatal ("%s: %m", PROCDEV_DEVICE);
377 while (fgets (buffer, sizeof buffer, proc_dev)) {
378 char *name = buffer;
379 char *sep;
381 /* Skip the first two blocks, which are header
382 lines. */
383 if (skip) {
384 --skip;
385 continue;
388 sep = strrchr (buffer, ':');
389 if (sep)
390 *sep = '\0';
391 while (*name == ' ')
392 name++;
394 /* See if we've seen an interface that matches
395 this one. */
396 for (tmp = interfaces; tmp; tmp = tmp -> next)
397 if (!strcmp (tmp -> name, name))
398 break;
400 /* If we found one, nothing more to do.. */
401 if (tmp)
402 continue;
404 strncpy (ifr.ifr_name, name, IFNAMSIZ);
406 /* Skip non broadcast interfaces (plus loopback and
407 * point-to-point in case an OS incorrectly marks them
408 * as broadcast).
410 #ifdef SOCKET_IS_NOT_A_FILE
411 if ((IoctlSocket (sock, SIOCGIFFLAGS, &ifr) < 0) ||
412 #else
413 if ((ioctl (sock, SIOCGIFFLAGS, &ifr) < 0) ||
414 #endif
415 (!(ifr.ifr_flags & IFF_BROADCAST)) ||
416 (ifr.ifr_flags & IFF_LOOPBACK ) ||
417 (ifr.ifr_flags & IFF_POINTOPOINT))
418 continue;
420 /* Otherwise, allocate one. */
421 tmp = (struct interface_info *)0;
422 status = interface_allocate (&tmp, MDL);
423 if (status != ISC_R_SUCCESS)
424 log_fatal ("Can't allocate interface %s: %s",
425 name, isc_result_totext (status));
426 tmp -> flags = ir;
427 strncpy (tmp -> name, name, IFNAMSIZ);
428 if (interfaces) {
429 interface_reference (&tmp -> next,
430 interfaces, MDL);
431 interface_dereference (&interfaces, MDL);
433 interface_reference (&interfaces, tmp, MDL);
434 interface_dereference (&tmp, MDL);
435 tmp = interfaces;
437 if (dhcp_interface_discovery_hook)
438 (*dhcp_interface_discovery_hook) (tmp);
441 fclose (proc_dev);
443 #endif
445 /* Now cycle through all the interfaces we found, looking for
446 hardware addresses. */
447 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
448 for (tmp = interfaces; tmp; tmp = tmp -> next) {
449 struct ifreq ifr;
450 struct sockaddr sa;
451 int b, sk;
453 if (!tmp -> ifp) {
454 /* Make up an ifreq structure. */
455 tif = (struct ifreq *)dmalloc (sizeof (struct ifreq),
456 MDL);
457 if (!tif)
458 log_fatal ("no space to remember ifp.");
459 memset (tif, 0, sizeof (struct ifreq));
460 strcpy (tif -> ifr_name, tmp -> name);
461 tmp -> ifp = tif;
464 /* Read the hardware address from this interface. */
465 ifr = *tmp -> ifp;
466 #ifdef SOCKET_IS_NOT_A_FILE
467 if (IoctlSocket (sock, SIOCGIFHWADDR, &ifr) <0)
468 #else
469 if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
470 #endif
471 continue;
473 sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
475 switch (sa.sa_family) {
476 #ifdef HAVE_ARPHRD_TUNNEL
477 case ARPHRD_TUNNEL:
478 /* ignore tunnel interfaces. */
479 #endif
480 #ifdef HAVE_ARPHRD_ROSE
481 case ARPHRD_ROSE:
482 #endif
483 #ifdef HAVE_ARPHRD_LOOPBACK
484 case ARPHRD_LOOPBACK:
485 /* ignore loopback interface */
486 break;
487 #endif
489 case ARPHRD_ETHER:
490 tmp -> hw_address.hlen = 7;
491 tmp -> hw_address.hbuf [0] = ARPHRD_ETHER;
492 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
493 break;
495 #ifndef HAVE_ARPHRD_IEEE802
496 # define ARPHRD_IEEE802 HTYPE_IEEE802
497 #endif
498 #if defined (HAVE_ARPHRD_IEEE802_TR)
499 case ARPHRD_IEEE802_TR:
500 #endif
501 case ARPHRD_IEEE802:
502 tmp -> hw_address.hlen = 7;
503 tmp -> hw_address.hbuf [0] = ARPHRD_IEEE802;
504 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
505 break;
507 #ifndef HAVE_ARPHRD_FDDI
508 # define ARPHRD_FDDI HTYPE_FDDI
509 #endif
510 case ARPHRD_FDDI:
511 tmp -> hw_address.hlen = 17;
512 tmp -> hw_address.hbuf [0] = HTYPE_FDDI; /* XXX */
513 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 16);
514 break;
516 #ifdef HAVE_ARPHRD_METRICOM
517 case ARPHRD_METRICOM:
518 tmp -> hw_address.hlen = 7;
519 tmp -> hw_address.hbuf [0] = ARPHRD_METRICOM;
520 memcpy (&tmp -> hw_address.hbuf [0], sa.sa_data, 6);
521 break;
522 #endif
524 #ifdef HAVE_ARPHRD_AX25
525 case ARPHRD_AX25:
526 tmp -> hw_address.hlen = 7;
527 tmp -> hw_address.hbuf [0] = ARPHRD_AX25;
528 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
529 break;
530 #endif
532 #ifdef HAVE_ARPHRD_NETROM
533 case ARPHRD_NETROM:
534 tmp -> hw_address.hlen = 7;
535 tmp -> hw_address.hbuf [0] = ARPHRD_NETROM;
536 memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
537 break;
538 #endif
540 default:
541 log_error ("%s: unknown hardware address type %d",
542 ifr.ifr_name, sa.sa_family);
543 break;
546 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
548 /* If we're just trying to get a list of interfaces that we might
549 be able to configure, we can quit now. */
550 if (state == DISCOVER_UNCONFIGURED) {
551 #ifdef SOCKET_IS_NOT_A_FILE
552 CloseSocket (sock);
553 #else
554 close (sock);
555 #endif
556 return;
559 /* Weed out the interfaces that did not have IP addresses. */
560 tmp = last = next = (struct interface_info *)0;
561 if (interfaces)
562 interface_reference (&tmp, interfaces, MDL);
563 while (tmp) {
564 if (next)
565 interface_dereference (&next, MDL);
566 if (tmp -> next)
567 interface_reference (&next, tmp -> next, MDL);
568 /* skip interfaces that are running already */
569 if (tmp -> flags & INTERFACE_RUNNING) {
570 interface_dereference(&tmp, MDL);
571 if(next)
572 interface_reference(&tmp, next, MDL);
573 continue;
575 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
576 state == DISCOVER_REQUESTED)
577 tmp -> flags &= ~(INTERFACE_AUTOMATIC |
578 INTERFACE_REQUESTED);
579 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
580 if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
581 log_fatal ("%s: not found", tmp -> name);
582 if (!last) {
583 if (interfaces)
584 interface_dereference (&interfaces,
585 MDL);
586 if (next)
587 interface_reference (&interfaces, next, MDL);
588 } else {
589 interface_dereference (&last -> next, MDL);
590 if (next)
591 interface_reference (&last -> next,
592 next, MDL);
594 if (tmp -> next)
595 interface_dereference (&tmp -> next, MDL);
597 /* Remember the interface in case we need to know
598 about it later. */
599 if (dummy_interfaces) {
600 interface_reference (&tmp -> next,
601 dummy_interfaces, MDL);
602 interface_dereference (&dummy_interfaces, MDL);
604 interface_reference (&dummy_interfaces, tmp, MDL);
605 interface_dereference (&tmp, MDL);
606 if (next)
607 interface_reference (&tmp, next, MDL);
608 continue;
610 last = tmp;
612 memcpy (&foo, &tmp -> ifp -> ifr_addr,
613 sizeof tmp -> ifp -> ifr_addr);
615 /* We must have a subnet declaration for each interface. */
616 if (!tmp -> shared_network && (state == DISCOVER_SERVER)) {
617 log_error ("%s", "");
618 log_error ("No subnet declaration for %s (%s).",
619 tmp -> name, inet_ntoa (foo.sin_addr));
620 if (supports_multiple_interfaces (tmp)) {
621 log_error ("** Ignoring requests on %s. %s",
622 tmp -> name, "If this is not what");
623 log_error (" you want, please write %s",
624 "a subnet declaration");
625 log_error (" in your dhcpd.conf file %s",
626 "for the network segment");
627 log_error (" to %s %s %s",
628 "which interface",
629 tmp -> name, "is attached. **");
630 log_error ("%s", "");
631 goto next;
632 } else {
633 log_error ("You must write a subnet %s",
634 " declaration for this");
635 log_error ("subnet. You cannot prevent %s",
636 "the DHCP server");
637 log_error ("from listening on this subnet %s",
638 "because your");
639 log_fatal ("operating system does not %s.",
640 "support this capability");
644 /* Find subnets that don't have valid interface
645 addresses... */
646 for (subnet = (tmp -> shared_network
647 ? tmp -> shared_network -> subnets
648 : (struct subnet *)0);
649 subnet; subnet = subnet -> next_sibling) {
650 if (!subnet -> interface_address.len) {
651 /* Set the interface address for this subnet
652 to the first address we found. */
653 subnet -> interface_address.len = 4;
654 memcpy (subnet -> interface_address.iabuf,
655 &foo.sin_addr.s_addr, 4);
659 /* Flag the index as not having been set, so that the
660 interface registerer can set it or not as it chooses. */
661 tmp -> index = -1;
663 /* Register the interface... */
664 if_register_receive (tmp);
665 if_register_send (tmp);
667 interface_stash (tmp);
668 wifcount++;
669 #if defined (HAVE_SETFD)
670 if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0)
671 log_error ("Can't set close-on-exec on %s: %m",
672 tmp -> name);
673 if (tmp -> rfdesc != tmp -> wfdesc) {
674 if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0)
675 log_error ("Can't set close-on-exec on %s: %m",
676 tmp -> name);
678 #endif
679 next:
680 interface_dereference (&tmp, MDL);
681 if (next)
682 interface_reference (&tmp, next, MDL);
685 /* Now register all the remaining interfaces as protocols. */
686 for (tmp = interfaces; tmp; tmp = tmp -> next) {
687 /* not if it's been registered before */
688 if (tmp -> flags & INTERFACE_RUNNING)
689 continue;
690 if (tmp -> rfdesc == -1)
691 continue;
692 status = omapi_register_io_object ((omapi_object_t *)tmp,
693 if_readsocket, 0,
694 got_one, 0, 0);
695 if (status != ISC_R_SUCCESS)
696 log_fatal ("Can't register I/O handle for %s: %s",
697 tmp -> name, isc_result_totext (status));
699 #ifdef SOCKET_IS_NOT_A_FILE
700 CloseSocket (sock);
701 #else
702 close (sock);
703 #endif
704 if (state == DISCOVER_SERVER && wifcount == 0) {
705 log_info ("%s", "");
706 log_fatal ("Not configured to listen on any interfaces!");
709 if (!setup_fallback) {
710 setup_fallback = 1;
711 maybe_setup_fallback ();
714 #if defined (HAVE_SETFD)
715 if (fallback_interface) {
716 if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
717 log_error ("Can't set close-on-exec on fallback: %m");
718 if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
719 if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
720 log_error ("Can't set close-on-exec on fallback: %m");
723 #endif
726 int if_readsocket (h)
727 omapi_object_t *h;
729 struct interface_info *ip;
731 if (h -> type != dhcp_type_interface)
732 return -1;
733 ip = (struct interface_info *)h;
734 return ip -> rfdesc;
737 int setup_fallback (struct interface_info **fp, const char *file, int line)
739 isc_result_t status;
741 status = interface_allocate (&fallback_interface, file, line);
742 if (status != ISC_R_SUCCESS)
743 log_fatal ("Error allocating fallback interface: %s",
744 isc_result_totext (status));
745 strcpy (fallback_interface -> name, "fallback");
746 if (dhcp_interface_setup_hook)
747 (*dhcp_interface_setup_hook) (fallback_interface,
748 (struct iaddr *)0);
749 status = interface_reference (fp, fallback_interface, file, line);
751 fallback_interface -> index = -1;
752 interface_stash (fallback_interface);
753 return status == ISC_R_SUCCESS;
756 void reinitialize_interfaces ()
758 struct interface_info *ip;
760 for (ip = interfaces; ip; ip = ip -> next) {
761 if_reinitialize_receive (ip);
762 if_reinitialize_send (ip);
765 if (fallback_interface)
766 if_reinitialize_send (fallback_interface);
768 interfaces_invalidated = 1;
771 isc_result_t got_one (h)
772 omapi_object_t *h;
774 struct sockaddr_in from;
775 struct hardware hfrom;
776 struct iaddr ifrom;
777 int result;
778 union {
779 unsigned char packbuf [4095]; /* Packet input buffer.
780 Must be as large as largest
781 possible MTU. */
782 struct dhcp_packet packet;
783 } u;
784 struct interface_info *ip;
786 if (h -> type != dhcp_type_interface)
787 return ISC_R_INVALIDARG;
788 ip = (struct interface_info *)h;
790 again:
791 if ((result =
792 receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
793 log_error ("receive_packet failed on %s: %m", ip -> name);
794 return ISC_R_UNEXPECTED;
796 if (result == 0)
797 return ISC_R_UNEXPECTED;
799 /* If we didn't at least get the fixed portion of the BOOTP
800 packet, drop the packet. We're allowing packets with no
801 sname or filename, because we're aware of at least one
802 client that sends such packets, but this definitely falls
803 into the category of being forgiving. */
804 if (result < DHCP_FIXED_NON_UDP - DHCP_SNAME_LEN - DHCP_FILE_LEN)
805 return ISC_R_UNEXPECTED;
807 if (bootp_packet_handler) {
808 ifrom.len = 4;
809 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
811 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
812 from.sin_port, ifrom, &hfrom);
815 /* If there is buffered data, read again. This is for, e.g.,
816 bpf, which may return two packets at once. */
817 if (ip -> rbuf_offset != ip -> rbuf_len)
818 goto again;
819 return ISC_R_SUCCESS;
822 isc_result_t dhcp_interface_set_value (omapi_object_t *h,
823 omapi_object_t *id,
824 omapi_data_string_t *name,
825 omapi_typed_data_t *value)
827 struct interface_info *interface;
828 isc_result_t status;
829 // int foo;
831 if (h -> type != dhcp_type_interface)
832 return ISC_R_INVALIDARG;
833 interface = (struct interface_info *)h;
835 if (!omapi_ds_strcmp (name, "name")) {
836 if ((value -> type == omapi_datatype_data ||
837 value -> type == omapi_datatype_string) &&
838 value -> u.buffer.len < sizeof interface -> name) {
839 memcpy (interface -> name,
840 value -> u.buffer.value,
841 value -> u.buffer.len);
842 interface -> name [value -> u.buffer.len] = 0;
843 } else
844 return ISC_R_INVALIDARG;
845 return ISC_R_SUCCESS;
848 /* Try to find some inner object that can take the value. */
849 if (h -> inner && h -> inner -> type -> set_value) {
850 status = ((*(h -> inner -> type -> set_value))
851 (h -> inner, id, name, value));
852 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
853 return status;
856 return ISC_R_NOTFOUND;
860 isc_result_t dhcp_interface_get_value (omapi_object_t *h,
861 omapi_object_t *id,
862 omapi_data_string_t *name,
863 omapi_value_t **value)
865 return ISC_R_NOTIMPLEMENTED;
868 isc_result_t dhcp_interface_destroy (omapi_object_t *h,
869 const char *file, int line)
871 struct interface_info *interface;
872 // isc_result_t status;
874 if (h -> type != dhcp_type_interface)
875 return ISC_R_INVALIDARG;
876 interface = (struct interface_info *)h;
878 if (interface -> ifp) {
879 dfree (interface -> ifp, file, line);
880 interface -> ifp = 0;
882 if (interface -> next)
883 interface_dereference (&interface -> next, file, line);
884 if (interface -> rbuf) {
885 dfree (interface -> rbuf, file, line);
886 interface -> rbuf = (unsigned char *)0;
888 if (interface -> client)
889 interface -> client = (struct client_state *)0;
891 if (interface -> shared_network)
892 omapi_object_dereference ((omapi_object_t **)
893 &interface -> shared_network, MDL);
895 return ISC_R_SUCCESS;
898 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
899 const char *name, va_list ap)
901 struct interface_info *ip, *interface;
902 // struct client_config *config;
903 // struct client_state *client;
904 isc_result_t status;
906 if (h -> type != dhcp_type_interface)
907 return ISC_R_INVALIDARG;
908 interface = (struct interface_info *)h;
910 /* If it's an update signal, see if the interface is dead right
911 now, or isn't known at all, and if that's the case, revive it. */
912 if (!strcmp (name, "update")) {
913 for (ip = dummy_interfaces; ip; ip = ip -> next)
914 if (ip == interface)
915 break;
916 if (ip && dhcp_interface_startup_hook)
917 return (*dhcp_interface_startup_hook) (ip);
919 for (ip = interfaces; ip; ip = ip -> next)
920 if (ip == interface)
921 break;
922 if (!ip && dhcp_interface_startup_hook)
923 return (*dhcp_interface_startup_hook) (ip);
926 /* Try to find some inner object that can take the value. */
927 if (h -> inner && h -> inner -> type -> get_value) {
928 status = ((*(h -> inner -> type -> signal_handler))
929 (h -> inner, name, ap));
930 if (status == ISC_R_SUCCESS)
931 return status;
933 return ISC_R_NOTFOUND;
936 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
937 omapi_object_t *id,
938 omapi_object_t *h)
940 struct interface_info *interface;
941 isc_result_t status;
943 if (h -> type != dhcp_type_interface)
944 return ISC_R_INVALIDARG;
945 interface = (struct interface_info *)h;
947 /* Write out all the values. */
949 status = omapi_connection_put_name (c, "state");
950 if (status != ISC_R_SUCCESS)
951 return status;
952 if (interface -> flags && INTERFACE_REQUESTED)
953 status = omapi_connection_put_string (c, "up");
954 else
955 status = omapi_connection_put_string (c, "down");
956 if (status != ISC_R_SUCCESS)
957 return status;
959 /* Write out the inner object, if any. */
960 if (h -> inner && h -> inner -> type -> stuff_values) {
961 status = ((*(h -> inner -> type -> stuff_values))
962 (c, id, h -> inner));
963 if (status == ISC_R_SUCCESS)
964 return status;
967 return ISC_R_SUCCESS;
970 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
971 omapi_object_t *id,
972 omapi_object_t *ref)
974 omapi_value_t *tv = (omapi_value_t *)0;
975 isc_result_t status;
976 struct interface_info *interface;
978 if (!ref)
979 return ISC_R_NOKEYS;
981 /* First see if we were sent a handle. */
982 status = omapi_get_value_str (ref, id, "handle", &tv);
983 if (status == ISC_R_SUCCESS) {
984 status = omapi_handle_td_lookup (ip, tv -> value);
986 omapi_value_dereference (&tv, MDL);
987 if (status != ISC_R_SUCCESS)
988 return status;
990 /* Don't return the object if the type is wrong. */
991 if ((*ip) -> type != dhcp_type_interface) {
992 omapi_object_dereference (ip, MDL);
993 return ISC_R_INVALIDARG;
997 /* Now look for an interface name. */
998 status = omapi_get_value_str (ref, id, "name", &tv);
999 if (status == ISC_R_SUCCESS) {
1000 char *s;
1001 unsigned len;
1002 for (interface = interfaces; interface;
1003 interface = interface -> next) {
1004 s = memchr (interface -> name, 0, IFNAMSIZ);
1005 if (s)
1006 len = s - &interface -> name [0];
1007 else
1008 len = IFNAMSIZ;
1009 if ((tv -> value -> u.buffer.len == len &&
1010 !memcmp (interface -> name,
1011 (char *)tv -> value -> u.buffer.value,
1012 len)))
1013 break;
1015 if (!interface) {
1016 for (interface = dummy_interfaces;
1017 interface; interface = interface -> next) {
1018 s = memchr (interface -> name, 0, IFNAMSIZ);
1019 if (s)
1020 len = s - &interface -> name [0];
1021 else
1022 len = IFNAMSIZ;
1023 if ((tv -> value -> u.buffer.len == len &&
1024 !memcmp (interface -> name,
1025 (char *)
1026 tv -> value -> u.buffer.value,
1027 len)))
1028 break;
1032 omapi_value_dereference (&tv, MDL);
1033 if (*ip && *ip != (omapi_object_t *)interface) {
1034 omapi_object_dereference (ip, MDL);
1035 return ISC_R_KEYCONFLICT;
1036 } else if (!interface) {
1037 if (*ip)
1038 omapi_object_dereference (ip, MDL);
1039 return ISC_R_NOTFOUND;
1040 } else if (!*ip)
1041 omapi_object_reference (ip,
1042 (omapi_object_t *)interface,
1043 MDL);
1046 /* If we get to here without finding an interface, no valid key was
1047 specified. */
1048 if (!*ip)
1049 return ISC_R_NOKEYS;
1050 return ISC_R_SUCCESS;
1053 /* actually just go discover the interface */
1054 isc_result_t dhcp_interface_create (omapi_object_t **lp,
1055 omapi_object_t *id)
1057 struct interface_info *hp;
1058 isc_result_t status;
1060 hp = (struct interface_info *)0;
1061 status = interface_allocate (&hp, MDL);
1062 if (status != ISC_R_SUCCESS)
1063 return status;
1064 hp -> flags = INTERFACE_REQUESTED;
1065 status = interface_reference ((struct interface_info **)lp, hp, MDL);
1066 interface_dereference (&hp, MDL);
1067 return status;
1070 isc_result_t dhcp_interface_remove (omapi_object_t *lp,
1071 omapi_object_t *id)
1073 struct interface_info *interface, *ip, *last;
1075 interface = (struct interface_info *)lp;
1077 /* remove from interfaces */
1078 last = 0;
1079 for (ip = interfaces; ip; ip = ip -> next) {
1080 if (ip == interface) {
1081 if (last) {
1082 interface_dereference (&last -> next, MDL);
1083 if (ip -> next)
1084 interface_reference (&last -> next,
1085 ip -> next, MDL);
1086 } else {
1087 interface_dereference (&interfaces, MDL);
1088 if (ip -> next)
1089 interface_reference (&interfaces,
1090 ip -> next, MDL);
1092 if (ip -> next)
1093 interface_dereference (&ip -> next, MDL);
1094 break;
1096 last = ip;
1098 if (!ip)
1099 return ISC_R_NOTFOUND;
1101 /* add the interface to the dummy_interface list */
1102 if (dummy_interfaces) {
1103 interface_reference (&interface -> next,
1104 dummy_interfaces, MDL);
1105 interface_dereference (&dummy_interfaces, MDL);
1107 interface_reference (&dummy_interfaces, interface, MDL);
1109 /* do a DHCPRELEASE */
1110 if (dhcp_interface_shutdown_hook)
1111 (*dhcp_interface_shutdown_hook) (interface);
1113 /* remove the io object */
1114 omapi_unregister_io_object ((omapi_object_t *)interface);
1116 if_deregister_send (interface);
1117 if_deregister_receive (interface);
1119 return ISC_R_SUCCESS;
1122 void interface_stash (struct interface_info *tptr)
1124 struct interface_info **vec;
1125 int delta;
1127 /* If the registerer didn't assign an index, assign one now. */
1128 if (tptr -> index == -1) {
1129 tptr -> index = interface_count++;
1130 while (tptr -> index < interface_max &&
1131 interface_vector [tptr -> index])
1132 tptr -> index = interface_count++;
1135 if (interface_max <= tptr -> index) {
1136 delta = tptr -> index - interface_max + 10;
1137 vec = dmalloc ((interface_max + delta) *
1138 sizeof (struct interface_info *), MDL);
1139 if (!vec)
1140 return;
1141 memset (&vec [interface_max], 0,
1142 (sizeof (struct interface_info *)) * delta);
1143 interface_max += delta;
1144 if (interface_vector) {
1145 memcpy (vec, interface_vector,
1146 (interface_count *
1147 sizeof (struct interface_info *)));
1148 dfree (interface_vector, MDL);
1150 interface_vector = vec;
1152 interface_reference (&interface_vector [tptr -> index], tptr, MDL);
1153 if (tptr -> index >= interface_count)
1154 interface_count = tptr -> index + 1;
1155 #if defined (TRACING)
1156 trace_interface_register (interface_trace, tptr);
1157 #endif
1160 void interface_snorf (struct interface_info *tmp, int ir)
1162 tmp -> circuit_id = (u_int8_t *)tmp -> name;
1163 tmp -> circuit_id_len = strlen (tmp -> name);
1164 tmp -> remote_id = 0;
1165 tmp -> remote_id_len = 0;
1166 tmp -> flags = ir;
1167 if (interfaces) {
1168 interface_reference (&tmp -> next,
1169 interfaces, MDL);
1170 interface_dereference (&interfaces, MDL);
1172 interface_reference (&interfaces, tmp, MDL);