Update isc-dhcp to 3.0.2rc3 using patch infrastructure.
[dragonfly.git] / contrib / dhcp-3.0 / common / discover.c
1 /* dispatch.c
2
3    Network input dispatcher... */
4
5 /*
6  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
7  * Copyright (c) 1995-2003 by Internet Software Consortium
8  *
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.
12  *
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.
20  *
21  *   Internet Systems Consortium, Inc.
22  *   950 Charter Street
23  *   Redwood City, CA 94063
24  *   <info@isc.org>
25  *   http://www.isc.org/
26  *
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''.
33  */
34
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 */
39
40 #include "dhcpd.h"
41 #include <sys/ioctl.h>
42
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 *);
52
53 struct in_addr limited_broadcast;
54 struct in_addr local_address;
55
56 void (*bootp_packet_handler) PROTO ((struct interface_info *,
57                                      struct dhcp_packet *, unsigned,
58                                      unsigned int,
59                                      struct iaddr, struct hardware *));
60
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;
70
71 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
72
73 isc_result_t interface_setup ()
74 {
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));
92
93         return status;
94 }
95
96 #if defined (TRACING)
97 void interface_trace_setup ()
98 {
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);
108 }
109 #endif
110
111 isc_result_t interface_initialize (omapi_object_t *ipo,
112                                    const char *file, int line)
113 {
114         struct interface_info *ip = (struct interface_info *)ipo;
115         ip -> rfdesc = ip -> wfdesc = -1;
116         return ISC_R_SUCCESS;
117 }
118
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. */
123
124 void discover_interfaces (state)
125         int state;
126 {
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;
146
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");
150
151         /* Get the interface configuration information... */
152
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.
156          * 
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. */
161
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 */
167
168         ic.ifc_len = sizeof buf;
169         ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
170 #endif
171
172       gifconf_again:
173         i = ioctl(sock, SIOCGIFCONF, &ic);
174
175         if (i < 0)
176                 log_fatal ("ioctl: SIOCGIFCONF: %m");
177
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;
184         }
185 #endif
186
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
204         }
205
206                 
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;
217
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;
227
228 #ifdef ALIAS_NAMES_PERMUTED
229                 if ((s = strrchr (ifp -> ifr_name, ':'))) {
230                         *s = 0;
231                 }
232 #endif
233
234 #ifdef SKIP_DUMMY_INTERFACES
235                 if (!strncmp (ifp -> ifr_name, "dummy", 5))
236                         continue;
237 #endif
238
239
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);
246
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;
251
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;
262                 
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 */
276                 }
277
278                 if (dhcp_interface_discovery_hook)
279                         (*dhcp_interface_discovery_hook) (tmp);
280
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 */
298
299                 if (ifp -> ifr_addr.sa_family == AF_INET) {
300                         struct iaddr addr;
301
302                         /* Get a pointer to the address... */
303                         memcpy (&foo, &ifp -> ifr_addr,
304                                 sizeof ifp -> ifr_addr);
305
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;
311
312
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;
329                         }
330
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);
337                 }
338         }
339
340         /* If we allocated a buffer, free it. */
341         if (ic.ifc_ifcu.ifcu_buf != buf)
342                 dfree (ic.ifc_ifcu.ifcu_buf, MDL);
343
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.
350
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. */
358
359         if (state == DISCOVER_UNCONFIGURED) {
360                 FILE *proc_dev;
361                 char buffer [256];
362                 int skip = 2;
363
364                 proc_dev = fopen (PROCDEV_DEVICE, "r");
365                 if (!proc_dev)
366                         log_fatal ("%s: %m", PROCDEV_DEVICE);
367
368                 while (fgets (buffer, sizeof buffer, proc_dev)) {
369                         char *name = buffer;
370                         char *sep;
371
372                         /* Skip the first two blocks, which are header
373                            lines. */
374                         if (skip) {
375                                 --skip;
376                                 continue;
377                         }
378
379                         sep = strrchr (buffer, ':');
380                         if (sep)
381                                 *sep = '\0';
382                         while (*name == ' ')
383                                 name++;
384
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;
390
391                         /* If we found one, nothing more to do.. */
392                         if (tmp)
393                                 continue;
394
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);
407                         }
408                         interface_reference (&interfaces, tmp, MDL);
409                         interface_dereference (&tmp, MDL);
410                         tmp = interfaces;
411
412                         if (dhcp_interface_discovery_hook)
413                                 (*dhcp_interface_discovery_hook) (tmp);
414
415                 }
416                 fclose (proc_dev);
417         }
418 #endif
419
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;
427                 
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;
437                 }
438
439                 /* Read the hardware address from this interface. */
440                 ifr = *tmp -> ifp;
441                 if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
442                         continue;
443                 
444                 sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
445                 
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
459
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;
465
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;
477
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;
486
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
494
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
502
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
510
511                       default:
512                         log_error ("%s: unknown hardware address type %d",
513                                    ifr.ifr_name, sa.sa_family);
514                         break;
515                 }
516         }
517 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
518
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;
524         }
525
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;
541                 }
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);
560                         }
561                         if (tmp -> next)
562                                 interface_dereference (&tmp -> next, MDL);
563
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);
570                         }
571                         interface_reference (&dummy_interfaces, tmp, MDL);
572                         interface_dereference (&tmp, MDL);
573                         if (next)
574                                 interface_reference (&tmp, next, MDL);
575                         continue;
576                 }
577                 last = tmp;
578
579                 memcpy (&foo, &tmp -> ifp -> ifr_addr,
580                         sizeof tmp -> ifp -> ifr_addr);
581
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");
608                         }
609                 }
610
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);
623                         }
624                 }
625
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;
629
630                 /* Register the interface... */
631                 if_register_receive (tmp);
632                 if_register_send (tmp);
633
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);
644                 }
645 #endif
646               next:
647                 interface_dereference (&tmp, MDL);
648                 if (next)
649                         interface_reference (&tmp, next, MDL);
650         }
651
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));
665         }
666
667         close (sock);
668
669         if (state == DISCOVER_SERVER && wifcount == 0) {
670                 log_info ("%s", "");
671                 log_fatal ("Not configured to listen on any interfaces!");
672         }
673
674         if (!setup_fallback) {
675                 setup_fallback = 1;
676                 maybe_setup_fallback ();
677         }
678
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");
686             }
687         }
688 #endif
689 }
690
691 int if_readsocket (h)
692         omapi_object_t *h;
693 {
694         struct interface_info *ip;
695
696         if (h -> type != dhcp_type_interface)
697                 return -1;
698         ip = (struct interface_info *)h;
699         return ip -> rfdesc;
700 }
701
702 int setup_fallback (struct interface_info **fp, const char *file, int line)
703 {
704         isc_result_t status;
705
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);
715
716         fallback_interface -> index = -1;
717         interface_stash (fallback_interface);
718         return status == ISC_R_SUCCESS;
719 }
720
721 void reinitialize_interfaces ()
722 {
723         struct interface_info *ip;
724
725         for (ip = interfaces; ip; ip = ip -> next) {
726                 if_reinitialize_receive (ip);
727                 if_reinitialize_send (ip);
728         }
729
730         if (fallback_interface)
731                 if_reinitialize_send (fallback_interface);
732
733         interfaces_invalidated = 1;
734 }
735
736 isc_result_t got_one (h)
737         omapi_object_t *h;
738 {
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;
750
751         if (h -> type != dhcp_type_interface)
752                 return ISC_R_INVALIDARG;
753         ip = (struct interface_info *)h;
754
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;
760         }
761         if (result == 0)
762                 return ISC_R_UNEXPECTED;
763
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;
771
772         if (bootp_packet_handler) {
773                 ifrom.len = 4;
774                 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
775
776                 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
777                                          from.sin_port, ifrom, &hfrom);
778         }
779
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;
785 }
786
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)
791 {
792         struct interface_info *interface;
793         isc_result_t status;
794         int foo;
795
796         if (h -> type != dhcp_type_interface)
797                 return ISC_R_INVALIDARG;
798         interface = (struct interface_info *)h;
799
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;
811         }
812
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;
819         }
820                           
821         return ISC_R_NOTFOUND;
822 }
823
824
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)
829 {
830         return ISC_R_NOTIMPLEMENTED;
831 }
832
833 isc_result_t dhcp_interface_destroy (omapi_object_t *h,
834                                          const char *file, int line)
835 {
836         struct interface_info *interface;
837         isc_result_t status;
838
839         if (h -> type != dhcp_type_interface)
840                 return ISC_R_INVALIDARG;
841         interface = (struct interface_info *)h;
842
843         if (interface -> ifp) {
844                 dfree (interface -> ifp, file, line);
845                 interface -> ifp = 0;
846         }
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;
852         }
853         if (interface -> client)
854                 interface -> client = (struct client_state *)0;
855
856         if (interface -> shared_network)
857                 omapi_object_dereference ((omapi_object_t **)
858                                           &interface -> shared_network, MDL);
859
860         return ISC_R_SUCCESS;
861 }
862
863 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
864                                             const char *name, va_list ap)
865 {
866         struct interface_info *ip, *interface;
867         struct client_config *config;
868         struct client_state *client;
869         isc_result_t status;
870
871         if (h -> type != dhcp_type_interface)
872                 return ISC_R_INVALIDARG;
873         interface = (struct interface_info *)h;
874
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);
883
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);
889         }
890
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;
897         }
898         return ISC_R_NOTFOUND;
899 }
900
901 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
902                                           omapi_object_t *id,
903                                           omapi_object_t *h)
904 {
905         struct interface_info *interface;
906         isc_result_t status;
907
908         if (h -> type != dhcp_type_interface)
909                 return ISC_R_INVALIDARG;
910         interface = (struct interface_info *)h;
911
912         /* Write out all the values. */
913
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;
923
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;
930         }
931
932         return ISC_R_SUCCESS;
933 }
934
935 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
936                                     omapi_object_t *id,
937                                     omapi_object_t *ref)
938 {
939         omapi_value_t *tv = (omapi_value_t *)0;
940         isc_result_t status;
941         struct interface_info *interface;
942
943         if (!ref)
944                 return ISC_R_NOKEYS;
945
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);
950
951                 omapi_value_dereference (&tv, MDL);
952                 if (status != ISC_R_SUCCESS)
953                         return status;
954
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;
959                 }
960         }
961
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;
979                 }
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;
994                     }
995                 }
996
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);
1009         }
1010
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;
1016 }
1017
1018 /* actually just go discover the interface */
1019 isc_result_t dhcp_interface_create (omapi_object_t **lp,
1020                                     omapi_object_t *id)
1021 {
1022         struct interface_info *hp;
1023         isc_result_t status;
1024         
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;
1033 }
1034
1035 isc_result_t dhcp_interface_remove (omapi_object_t *lp,
1036                                     omapi_object_t *id)
1037 {
1038         struct interface_info *interface, *ip, *last;
1039
1040         interface = (struct interface_info *)lp;
1041
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);
1056                         }
1057                         if (ip -> next)
1058                                 interface_dereference (&ip -> next, MDL);
1059                         break;
1060                 }
1061                 last = ip;
1062         }
1063         if (!ip)
1064                 return ISC_R_NOTFOUND;
1065
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);
1071         }
1072         interface_reference (&dummy_interfaces, interface, MDL);
1073
1074         /* do a DHCPRELEASE */
1075         if (dhcp_interface_shutdown_hook)
1076                 (*dhcp_interface_shutdown_hook) (interface);
1077
1078         /* remove the io object */
1079         omapi_unregister_io_object ((omapi_object_t *)interface);
1080
1081         if_deregister_send (interface);
1082         if_deregister_receive (interface);
1083
1084         return ISC_R_SUCCESS;
1085 }
1086
1087 void interface_stash (struct interface_info *tptr)
1088 {
1089         struct interface_info **vec;
1090         int delta;
1091
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++;
1098         }
1099
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);
1114                 }
1115                 interface_vector = vec;
1116         }
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
1123 }
1124
1125 void interface_snorf (struct interface_info *tmp, int ir)
1126 {
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);
1136         }
1137         interface_reference (&interfaces, tmp, MDL);
1138 }