Make setthetime() static per the prototype.
[dragonfly.git] / contrib / isc-dhcp / common / discover.c
1 /* dispatch.c
2
3    Network input dispatcher... */
4
5 /*
6  * Copyright (c) 1995-2002 Internet Software Consortium.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of The Internet Software Consortium nor the names
19  *    of its contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * This software has been written for the Internet Software Consortium
37  * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
38  * To learn more about the Internet Software Consortium, see
39  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
40  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
41  * ``http://www.nominum.com''.
42  * 
43  * $Id: discover.c,v 1.42.2.14 2003/07/25 19:44:15 dhankins Exp $ Copyright (c) 1995-2002 The Internet Software Consortium.  All rights reserved.
44  * $DragonFly: src/contrib/isc-dhcp/common/Attic/discover.c,v 1.2 2003/10/11 21:14:17 dillon Exp $
45  */
46
47 #include "dhcpd.h"
48 #include <sys/ioctl.h>
49
50 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
51 int interfaces_invalidated;
52 int quiet_interface_discovery;
53 u_int16_t local_port;
54 u_int16_t remote_port;
55 int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
56 int (*dhcp_interface_discovery_hook) (struct interface_info *);
57 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
58 int (*dhcp_interface_shutdown_hook) (struct interface_info *);
59
60 struct in_addr limited_broadcast;
61 struct in_addr local_address;
62
63 void (*bootp_packet_handler) PROTO ((struct interface_info *,
64                                      struct dhcp_packet *, unsigned,
65                                      unsigned int,
66                                      struct iaddr, struct hardware *));
67
68 omapi_object_type_t *dhcp_type_interface;
69 #if defined (TRACING)
70 trace_type_t *interface_trace;
71 trace_type_t *inpacket_trace;
72 trace_type_t *outpacket_trace;
73 #endif
74 struct interface_info **interface_vector;
75 int interface_count;
76 int interface_max;
77
78 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
79
80 isc_result_t interface_setup ()
81 {
82         isc_result_t status;
83         status = omapi_object_type_register (&dhcp_type_interface,
84                                              "interface",
85                                              dhcp_interface_set_value,
86                                              dhcp_interface_get_value,
87                                              dhcp_interface_destroy,
88                                              dhcp_interface_signal_handler,
89                                              dhcp_interface_stuff_values,
90                                              dhcp_interface_lookup, 
91                                              dhcp_interface_create,
92                                              dhcp_interface_remove,
93                                              0, 0, 0,
94                                              sizeof (struct interface_info),
95                                              interface_initialize, RC_MISC);
96         if (status != ISC_R_SUCCESS)
97                 log_fatal ("Can't register interface object type: %s",
98                            isc_result_totext (status));
99
100         return status;
101 }
102
103 #if defined (TRACING)
104 void interface_trace_setup ()
105 {
106         interface_trace = trace_type_register ("interface", (void *)0,
107                                                trace_interface_input,
108                                                trace_interface_stop, MDL);
109         inpacket_trace = trace_type_register ("inpacket", (void *)0,
110                                                trace_inpacket_input,
111                                                trace_inpacket_stop, MDL);
112         outpacket_trace = trace_type_register ("outpacket", (void *)0,
113                                                trace_outpacket_input,
114                                                trace_outpacket_stop, MDL);
115 }
116 #endif
117
118 isc_result_t interface_initialize (omapi_object_t *ipo,
119                                    const char *file, int line)
120 {
121         struct interface_info *ip = (struct interface_info *)ipo;
122         ip -> rfdesc = ip -> wfdesc = -1;
123         return ISC_R_SUCCESS;
124 }
125
126 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
127    For each interface that's of type INET and not the loopback interface,
128    register that interface with the network I/O software, figure out what
129    subnet it's on, and add it to the list of interfaces. */
130
131 void discover_interfaces (state)
132         int state;
133 {
134         struct interface_info *tmp, *ip;
135         struct interface_info *last, *next;
136         char buf [2048];
137         struct ifconf ic;
138         struct ifreq ifr;
139         int i;
140         int sock;
141         int address_count = 0;
142         struct subnet *subnet;
143         struct shared_network *share;
144         struct sockaddr_in foo;
145         int ir;
146         struct ifreq *tif;
147 #ifdef ALIAS_NAMES_PERMUTED
148         char *s;
149 #endif
150         isc_result_t status;
151         static int setup_fallback = 0;
152         int wifcount = 0;
153
154         /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
155         if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
156                 log_fatal ("Can't create addrlist socket");
157
158         /* Get the interface configuration information... */
159
160 #ifdef SIOCGIFCONF_ZERO_PROBE
161         /* linux will only tell us how long a buffer it wants if we give it
162          * a null buffer first. So, do a dry run to figure out the length.
163          * 
164          * XXX this code is duplicated from below because trying to fold
165          * the logic into the if statement and goto resulted in excesssive
166          * obfuscation. The intent is that unless you run Linux you shouldn't
167          * have to deal with this. */
168
169         ic.ifc_len = 0;
170         ic.ifc_ifcu.ifcu_buf = (caddr_t)NULL;
171 #else
172         /* otherwise, we just feed it a starting size, and it'll tell us if
173          * it needs more */
174
175         ic.ifc_len = sizeof buf;
176         ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
177 #endif
178
179       gifconf_again:
180         i = ioctl(sock, SIOCGIFCONF, &ic);
181
182         if (i < 0)
183                 log_fatal ("ioctl: SIOCGIFCONF: %m");
184
185 #ifdef SIOCGIFCONF_ZERO_PROBE
186         /* Workaround for SIOCGIFCONF bug on some Linux versions. */
187         if (ic.ifc_ifcu.ifcu_buf == 0 && ic.ifc_len == 0) {
188                 ic.ifc_len = sizeof buf;
189                 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
190                 goto gifconf_again;
191         }
192 #endif
193
194         /* If the SIOCGIFCONF resulted in more data than would fit in
195            a buffer, allocate a bigger buffer. */
196         if ((ic.ifc_ifcu.ifcu_buf == buf 
197 #ifdef SIOCGIFCONF_ZERO_PROBE
198              || ic.ifc_ifcu.ifcu_buf == 0
199 #endif
200                 ) && ic.ifc_len > sizeof buf) {
201                 ic.ifc_ifcu.ifcu_buf = dmalloc ((size_t)ic.ifc_len, MDL);
202                 if (!ic.ifc_ifcu.ifcu_buf)
203                         log_fatal ("Can't allocate SIOCGIFCONF buffer.");
204                 goto gifconf_again;
205 #ifdef SIOCGIFCONF_ZERO_PROBE
206         } else if (ic.ifc_ifcu.ifcu_buf == 0) {
207                 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
208                 ic.ifc_len = sizeof buf;
209                 goto gifconf_again;
210 #endif
211         }
212
213                 
214         /* If we already have a list of interfaces, and we're running as
215            a DHCP server, the interfaces were requested. */
216         if (interfaces && (state == DISCOVER_SERVER ||
217                            state == DISCOVER_RELAY ||
218                            state == DISCOVER_REQUESTED))
219                 ir = 0;
220         else if (state == DISCOVER_UNCONFIGURED)
221                 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
222         else
223                 ir = INTERFACE_REQUESTED;
224
225         /* Cycle through the list of interfaces looking for IP addresses. */
226         for (i = 0; i < ic.ifc_len;) {
227                 struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
228 #ifdef HAVE_SA_LEN
229                 if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr))
230                         i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
231                 else
232 #endif
233                         i += sizeof *ifp;
234
235 #ifdef ALIAS_NAMES_PERMUTED
236                 if ((s = strrchr (ifp -> ifr_name, ':'))) {
237                         *s = 0;
238                 }
239 #endif
240
241 #ifdef SKIP_DUMMY_INTERFACES
242                 if (!strncmp (ifp -> ifr_name, "dummy", 5))
243                         continue;
244 #endif
245
246
247                 /* See if this is the sort of interface we want to
248                    deal with. */
249                 strcpy (ifr.ifr_name, ifp -> ifr_name);
250                 if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
251                         log_fatal ("Can't get interface flags for %s: %m",
252                                ifr.ifr_name);
253
254                 /* See if we've seen an interface that matches this one. */
255                 for (tmp = interfaces; tmp; tmp = tmp -> next)
256                         if (!strcmp (tmp -> name, ifp -> ifr_name))
257                                 break;
258
259                 /* Skip non broadcast interfaces (plus loopback and
260                    point-to-point in case an OS incorrectly marks them
261                    as broadcast). Also skip down interfaces unless we're
262                    trying to get a list of configurable interfaces. */
263                 if (((!(ifr.ifr_flags & IFF_BROADCAST) ||
264                       ifr.ifr_flags & IFF_LOOPBACK ||
265                       ifr.ifr_flags & IFF_POINTOPOINT) && !tmp) ||
266                     (!(ifr.ifr_flags & IFF_UP) &&
267                      state != DISCOVER_UNCONFIGURED))
268                         continue;
269                 
270                 /* If there isn't already an interface by this name,
271                    allocate one. */
272                 if (!tmp) {
273                         tmp = (struct interface_info *)0;
274                         status = interface_allocate (&tmp, MDL);
275                         if (status != ISC_R_SUCCESS)
276                                 log_fatal ("Error allocating interface %s: %s",
277                                            ifp -> ifr_name,
278                                            isc_result_totext (status));
279                         strcpy (tmp -> name, ifp -> ifr_name);
280                         interface_snorf (tmp, ir);
281                         interface_dereference (&tmp, MDL);
282                         tmp = interfaces; /* XXX */
283                 }
284
285                 if (dhcp_interface_discovery_hook)
286                         (*dhcp_interface_discovery_hook) (tmp);
287
288                 /* If we have the capability, extract link information
289                    and record it in a linked list. */
290 #ifdef HAVE_AF_LINK
291                 if (ifp -> ifr_addr.sa_family == AF_LINK) {
292                         struct sockaddr_dl *foo = ((struct sockaddr_dl *)
293                                                    (&ifp -> ifr_addr));
294 #if defined (HAVE_SIN_LEN)
295                         tmp -> hw_address.hlen = foo -> sdl_alen;
296 #else
297                         tmp -> hw_address.hlen = 6; /* XXX!!! */
298 #endif
299                         tmp -> hw_address.hbuf [0] = HTYPE_ETHER; /* XXX */
300                         memcpy (&tmp -> hw_address.hbuf [1],
301                                 LLADDR (foo), tmp -> hw_address.hlen);
302                         tmp -> hw_address.hlen++;       /* for type. */
303                 } else
304 #endif /* AF_LINK */
305
306                 if (ifp -> ifr_addr.sa_family == AF_INET) {
307                         struct iaddr addr;
308
309                         /* Get a pointer to the address... */
310                         memcpy (&foo, &ifp -> ifr_addr,
311                                 sizeof ifp -> ifr_addr);
312
313                         /* We don't want the loopback interface. */
314                         if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK) &&
315                             ((tmp -> flags & INTERFACE_AUTOMATIC) &&
316                              state == DISCOVER_SERVER))
317                             continue;
318
319
320                         /* If this is the first real IP address we've
321                            found, keep a pointer to ifreq structure in
322                            which we found it. */
323                         if (!tmp -> ifp) {
324 #ifdef HAVE_SA_LEN
325                                 unsigned len = ((sizeof ifp -> ifr_name) +
326                                                 ifp -> ifr_addr.sa_len);
327 #else
328                                 unsigned len = sizeof *ifp;
329 #endif
330                                 tif = (struct ifreq *)dmalloc (len, MDL);
331                                 if (!tif)
332                                         log_fatal ("no space for ifp.");
333                                 memcpy (tif, ifp, len);
334                                 tmp -> ifp = tif;
335                                 tmp -> primary_address = foo.sin_addr;
336                         }
337
338                         /* Grab the address... */
339                         addr.len = 4;
340                         memcpy (addr.iabuf, &foo.sin_addr.s_addr,
341                                 addr.len);
342                         if (dhcp_interface_setup_hook)
343                                 (*dhcp_interface_setup_hook) (tmp, &addr);
344                 }
345         }
346
347         /* If we allocated a buffer, free it. */
348         if (ic.ifc_ifcu.ifcu_buf != buf)
349                 dfree (ic.ifc_ifcu.ifcu_buf, MDL);
350
351 #if defined (LINUX_SLASHPROC_DISCOVERY)
352         /* On Linux, interfaces that don't have IP addresses don't
353            show up in the SIOCGIFCONF syscall.  This only matters for
354            the DHCP client, of course - the relay agent and server
355            should only care about interfaces that are configured with
356            IP addresses anyway.
357
358            The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
359            that, when read, prints a human readable network status.   We
360            extract the names of the network devices by skipping the first
361            two lines (which are header) and then parsing off everything
362            up to the colon in each subsequent line - these lines start
363            with the interface name, then a colon, then a bunch of
364            statistics. */
365
366         if (state == DISCOVER_UNCONFIGURED) {
367                 FILE *proc_dev;
368                 char buffer [256];
369                 int skip = 2;
370
371                 proc_dev = fopen (PROCDEV_DEVICE, "r");
372                 if (!proc_dev)
373                         log_fatal ("%s: %m", PROCDEV_DEVICE);
374
375                 while (fgets (buffer, sizeof buffer, proc_dev)) {
376                         char *name = buffer;
377                         char *sep;
378
379                         /* Skip the first two blocks, which are header
380                            lines. */
381                         if (skip) {
382                                 --skip;
383                                 continue;
384                         }
385
386                         sep = strrchr (buffer, ':');
387                         if (sep)
388                                 *sep = '\0';
389                         while (*name == ' ')
390                                 name++;
391
392                         /* See if we've seen an interface that matches
393                            this one. */
394                         for (tmp = interfaces; tmp; tmp = tmp -> next)
395                                 if (!strcmp (tmp -> name, name))
396                                         break;
397
398                         /* If we found one, nothing more to do.. */
399                         if (tmp)
400                                 continue;
401
402                         /* Otherwise, allocate one. */
403                         tmp = (struct interface_info *)0;
404                         status = interface_allocate (&tmp, MDL);
405                         if (status != ISC_R_SUCCESS)
406                                 log_fatal ("Can't allocate interface %s: %s",
407                                            name, isc_result_totext (status));
408                         tmp -> flags = ir;
409                         strncpy (tmp -> name, name, IFNAMSIZ);
410                         if (interfaces) {
411                                 interface_reference (&tmp -> next,
412                                                      interfaces, MDL);
413                                 interface_dereference (&interfaces, MDL);
414                         }
415                         interface_reference (&interfaces, tmp, MDL);
416                         interface_dereference (&tmp, MDL);
417                         tmp = interfaces;
418
419                         if (dhcp_interface_discovery_hook)
420                                 (*dhcp_interface_discovery_hook) (tmp);
421
422                 }
423                 fclose (proc_dev);
424         }
425 #endif
426
427         /* Now cycle through all the interfaces we found, looking for
428            hardware addresses. */
429 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
430         for (tmp = interfaces; tmp; tmp = tmp -> next) {
431                 struct ifreq ifr;
432                 struct sockaddr sa;
433                 int b, sk;
434                 
435                 if (!tmp -> ifp) {
436                         /* Make up an ifreq structure. */
437                         tif = (struct ifreq *)dmalloc (sizeof (struct ifreq),
438                                                        MDL);
439                         if (!tif)
440                                 log_fatal ("no space to remember ifp.");
441                         memset (tif, 0, sizeof (struct ifreq));
442                         strcpy (tif -> ifr_name, tmp -> name);
443                         tmp -> ifp = tif;
444                 }
445
446                 /* Read the hardware address from this interface. */
447                 ifr = *tmp -> ifp;
448                 if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
449                         continue;
450                 
451                 sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
452                 
453                 switch (sa.sa_family) {
454 #ifdef HAVE_ARPHRD_TUNNEL
455                       case ARPHRD_TUNNEL:
456                         /* ignore tunnel interfaces. */
457 #endif
458 #ifdef HAVE_ARPHRD_ROSE
459                       case ARPHRD_ROSE:
460 #endif
461 #ifdef HAVE_ARPHRD_LOOPBACK
462                       case ARPHRD_LOOPBACK:
463                         /* ignore loopback interface */
464                         break;
465 #endif
466
467                       case ARPHRD_ETHER:
468                         tmp -> hw_address.hlen = 7;
469                         tmp -> hw_address.hbuf [0] = ARPHRD_ETHER;
470                         memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
471                         break;
472
473 #ifndef HAVE_ARPHRD_IEEE802
474 # define ARPHRD_IEEE802 HTYPE_IEEE802
475 #endif
476 #if defined (HAVE_ARPHRD_IEEE802_TR)
477                       case ARPHRD_IEEE802_TR:
478 #endif
479                       case ARPHRD_IEEE802:
480                         tmp -> hw_address.hlen = 7;
481                         tmp -> hw_address.hbuf [0] = ARPHRD_IEEE802;
482                         memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
483                         break;
484
485 #ifndef HAVE_ARPHRD_FDDI
486 # define ARPHRD_FDDI HTYPE_FDDI
487 #endif
488                       case ARPHRD_FDDI:
489                         tmp -> hw_address.hlen = 17;
490                         tmp -> hw_address.hbuf [0] = HTYPE_FDDI; /* XXX */
491                         memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 16);
492                         break;
493
494 #ifdef HAVE_ARPHRD_METRICOM
495                       case ARPHRD_METRICOM:
496                         tmp -> hw_address.hlen = 7;
497                         tmp -> hw_address.hbuf [0] = ARPHRD_METRICOM;
498                         memcpy (&tmp -> hw_address.hbuf [0], sa.sa_data, 6);
499                         break;
500 #endif
501
502 #ifdef HAVE_ARPHRD_AX25
503                       case ARPHRD_AX25:
504                         tmp -> hw_address.hlen = 7;
505                         tmp -> hw_address.hbuf [0] = ARPHRD_AX25;
506                         memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
507                         break;
508 #endif
509
510 #ifdef HAVE_ARPHRD_NETROM
511                       case ARPHRD_NETROM:
512                         tmp -> hw_address.hlen = 7;
513                         tmp -> hw_address.hbuf [0] = ARPHRD_NETROM;
514                         memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
515                         break;
516 #endif
517
518                       default:
519                         log_error ("%s: unknown hardware address type %d",
520                                    ifr.ifr_name, sa.sa_family);
521                         break;
522                 }
523         }
524 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
525
526         /* If we're just trying to get a list of interfaces that we might
527            be able to configure, we can quit now. */
528         if (state == DISCOVER_UNCONFIGURED) {
529                 close (sock);
530                 return;
531         }
532
533         /* Weed out the interfaces that did not have IP addresses. */
534         tmp = last = next = (struct interface_info *)0;
535         if (interfaces)
536                 interface_reference (&tmp, interfaces, MDL);
537         while (tmp) {
538                 if (next)
539                         interface_dereference (&next, MDL);
540                 if (tmp -> next)
541                         interface_reference (&next, tmp -> next, MDL);
542                 /* skip interfaces that are running already */
543                 if (tmp -> flags & INTERFACE_RUNNING) {
544                         interface_dereference(&tmp, MDL);
545                         if(next)
546                                 interface_reference(&tmp, next, MDL);
547                         continue;
548                 }
549                 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
550                     state == DISCOVER_REQUESTED)
551                         tmp -> flags &= ~(INTERFACE_AUTOMATIC |
552                                           INTERFACE_REQUESTED);
553                 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
554                         if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
555                                 log_fatal ("%s: not found", tmp -> name);
556                         if (!last) {
557                                 if (interfaces)
558                                         interface_dereference (&interfaces,
559                                                                MDL);
560                                 if (next)
561                                 interface_reference (&interfaces, next, MDL);
562                         } else {
563                                 interface_dereference (&last -> next, MDL);
564                                 if (next)
565                                         interface_reference (&last -> next,
566                                                              next, MDL);
567                         }
568                         if (tmp -> next)
569                                 interface_dereference (&tmp -> next, MDL);
570
571                         /* Remember the interface in case we need to know
572                            about it later. */
573                         if (dummy_interfaces) {
574                                 interface_reference (&tmp -> next,
575                                                      dummy_interfaces, MDL);
576                                 interface_dereference (&dummy_interfaces, MDL);
577                         }
578                         interface_reference (&dummy_interfaces, tmp, MDL);
579                         interface_dereference (&tmp, MDL);
580                         if (next)
581                                 interface_reference (&tmp, next, MDL);
582                         continue;
583                 }
584                 last = tmp;
585
586                 memcpy (&foo, &tmp -> ifp -> ifr_addr,
587                         sizeof tmp -> ifp -> ifr_addr);
588
589                 /* We must have a subnet declaration for each interface. */
590                 if (!tmp -> shared_network && (state == DISCOVER_SERVER)) {
591                         log_error ("%s", "");
592                         log_error ("No subnet declaration for %s (%s).",
593                                    tmp -> name, inet_ntoa (foo.sin_addr));
594                         if (supports_multiple_interfaces (tmp)) {
595                                 log_error ("** Ignoring requests on %s.  %s",
596                                            tmp -> name, "If this is not what");
597                                 log_error ("   you want, please write %s",
598                                            "a subnet declaration");
599                                 log_error ("   in your dhcpd.conf file %s",
600                                            "for the network segment");
601                                 log_error ("   to %s %s %s",
602                                            "which interface",
603                                            tmp -> name, "is attached. **");
604                                 log_error ("%s", "");
605                                 goto next;
606                         } else {
607                                 log_error ("You must write a subnet %s",
608                                            " declaration for this");
609                                 log_error ("subnet.   You cannot prevent %s",
610                                            "the DHCP server");
611                                 log_error ("from listening on this subnet %s",
612                                            "because your");
613                                 log_fatal ("operating system does not %s.",
614                                            "support this capability");
615                         }
616                 }
617
618                 /* Find subnets that don't have valid interface
619                    addresses... */
620                 for (subnet = (tmp -> shared_network
621                                ? tmp -> shared_network -> subnets
622                                : (struct subnet *)0);
623                      subnet; subnet = subnet -> next_sibling) {
624                         if (!subnet -> interface_address.len) {
625                                 /* Set the interface address for this subnet
626                                    to the first address we found. */
627                                 subnet -> interface_address.len = 4;
628                                 memcpy (subnet -> interface_address.iabuf,
629                                         &foo.sin_addr.s_addr, 4);
630                         }
631                 }
632
633                 /* Flag the index as not having been set, so that the
634                    interface registerer can set it or not as it chooses. */
635                 tmp -> index = -1;
636
637                 /* Register the interface... */
638                 if_register_receive (tmp);
639                 if_register_send (tmp);
640
641                 interface_stash (tmp);
642                 wifcount++;
643 #if defined (HAVE_SETFD)
644                 if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0)
645                         log_error ("Can't set close-on-exec on %s: %m",
646                                    tmp -> name);
647                 if (tmp -> rfdesc != tmp -> wfdesc) {
648                         if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0)
649                                 log_error ("Can't set close-on-exec on %s: %m",
650                                            tmp -> name);
651                 }
652 #endif
653               next:
654                 interface_dereference (&tmp, MDL);
655                 if (next)
656                         interface_reference (&tmp, next, MDL);
657         }
658
659         /* Now register all the remaining interfaces as protocols. */
660         for (tmp = interfaces; tmp; tmp = tmp -> next) {
661                 /* not if it's been registered before */
662                 if (tmp -> flags & INTERFACE_RUNNING)
663                         continue;
664                 if (tmp -> rfdesc == -1)
665                         continue;
666                 status = omapi_register_io_object ((omapi_object_t *)tmp,
667                                                    if_readsocket, 0,
668                                                    got_one, 0, 0);
669                 if (status != ISC_R_SUCCESS)
670                         log_fatal ("Can't register I/O handle for %s: %s",
671                                    tmp -> name, isc_result_totext (status));
672         }
673
674         close (sock);
675
676         if (state == DISCOVER_SERVER && wifcount == 0) {
677                 log_info ("%s", "");
678                 log_fatal ("Not configured to listen on any interfaces!");
679         }
680
681         if (!setup_fallback) {
682                 setup_fallback = 1;
683                 maybe_setup_fallback ();
684         }
685
686 #if defined (HAVE_SETFD)
687         if (fallback_interface) {
688             if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
689                 log_error ("Can't set close-on-exec on fallback: %m");
690             if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
691                 if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
692                     log_error ("Can't set close-on-exec on fallback: %m");
693             }
694         }
695 #endif
696 }
697
698 int if_readsocket (h)
699         omapi_object_t *h;
700 {
701         struct interface_info *ip;
702
703         if (h -> type != dhcp_type_interface)
704                 return -1;
705         ip = (struct interface_info *)h;
706         return ip -> rfdesc;
707 }
708
709 int setup_fallback (struct interface_info **fp, const char *file, int line)
710 {
711         isc_result_t status;
712
713         status = interface_allocate (&fallback_interface, file, line);
714         if (status != ISC_R_SUCCESS)
715                 log_fatal ("Error allocating fallback interface: %s",
716                            isc_result_totext (status));
717         strcpy (fallback_interface -> name, "fallback");
718         if (dhcp_interface_setup_hook)
719                 (*dhcp_interface_setup_hook) (fallback_interface,
720                                               (struct iaddr *)0);
721         status = interface_reference (fp, fallback_interface, file, line);
722
723         fallback_interface -> index = -1;
724         interface_stash (fallback_interface);
725         return status == ISC_R_SUCCESS;
726 }
727
728 void reinitialize_interfaces ()
729 {
730         struct interface_info *ip;
731
732         for (ip = interfaces; ip; ip = ip -> next) {
733                 if_reinitialize_receive (ip);
734                 if_reinitialize_send (ip);
735         }
736
737         if (fallback_interface)
738                 if_reinitialize_send (fallback_interface);
739
740         interfaces_invalidated = 1;
741 }
742
743 isc_result_t got_one (h)
744         omapi_object_t *h;
745 {
746         struct sockaddr_in from;
747         struct hardware hfrom;
748         struct iaddr ifrom;
749         int result;
750         union {
751                 unsigned char packbuf [4095]; /* Packet input buffer.
752                                                  Must be as large as largest
753                                                  possible MTU. */
754                 struct dhcp_packet packet;
755         } u;
756         struct interface_info *ip;
757
758         if (h -> type != dhcp_type_interface)
759                 return ISC_R_INVALIDARG;
760         ip = (struct interface_info *)h;
761
762       again:
763         if ((result =
764              receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
765                 log_error ("receive_packet failed on %s: %m", ip -> name);
766                 return ISC_R_UNEXPECTED;
767         }
768         if (result == 0)
769                 return ISC_R_UNEXPECTED;
770
771         /* If we didn't at least get the fixed portion of the BOOTP
772            packet, drop the packet.  We're allowing packets with no
773            sname or filename, because we're aware of at least one
774            client that sends such packets, but this definitely falls
775            into the category of being forgiving. */
776         if (result < DHCP_FIXED_NON_UDP - DHCP_SNAME_LEN - DHCP_FILE_LEN)
777                 return ISC_R_UNEXPECTED;
778
779         if (bootp_packet_handler) {
780                 ifrom.len = 4;
781                 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
782
783                 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
784                                          from.sin_port, ifrom, &hfrom);
785         }
786
787         /* If there is buffered data, read again.    This is for, e.g.,
788            bpf, which may return two packets at once. */
789         if (ip -> rbuf_offset != ip -> rbuf_len)
790                 goto again;
791         return ISC_R_SUCCESS;
792 }
793
794 isc_result_t dhcp_interface_set_value  (omapi_object_t *h,
795                                         omapi_object_t *id,
796                                         omapi_data_string_t *name,
797                                         omapi_typed_data_t *value)
798 {
799         struct interface_info *interface;
800         isc_result_t status;
801         int foo;
802
803         if (h -> type != dhcp_type_interface)
804                 return ISC_R_INVALIDARG;
805         interface = (struct interface_info *)h;
806
807         if (!omapi_ds_strcmp (name, "name")) {
808                 if ((value -> type == omapi_datatype_data ||
809                      value -> type == omapi_datatype_string) &&
810                     value -> u.buffer.len < sizeof interface -> name) {
811                         memcpy (interface -> name,
812                                 value -> u.buffer.value,
813                                 value -> u.buffer.len);
814                         interface -> name [value -> u.buffer.len] = 0;
815                 } else
816                         return ISC_R_INVALIDARG;
817                 return ISC_R_SUCCESS;
818         }
819
820         /* Try to find some inner object that can take the value. */
821         if (h -> inner && h -> inner -> type -> set_value) {
822                 status = ((*(h -> inner -> type -> set_value))
823                           (h -> inner, id, name, value));
824                 if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
825                         return status;
826         }
827                           
828         return ISC_R_NOTFOUND;
829 }
830
831
832 isc_result_t dhcp_interface_get_value (omapi_object_t *h,
833                                        omapi_object_t *id,
834                                        omapi_data_string_t *name,
835                                        omapi_value_t **value)
836 {
837         return ISC_R_NOTIMPLEMENTED;
838 }
839
840 isc_result_t dhcp_interface_destroy (omapi_object_t *h,
841                                          const char *file, int line)
842 {
843         struct interface_info *interface;
844         isc_result_t status;
845
846         if (h -> type != dhcp_type_interface)
847                 return ISC_R_INVALIDARG;
848         interface = (struct interface_info *)h;
849
850         if (interface -> ifp) {
851                 dfree (interface -> ifp, file, line);
852                 interface -> ifp = 0;
853         }
854         if (interface -> next)
855                 interface_dereference (&interface -> next, file, line);
856         if (interface -> rbuf) {
857                 dfree (interface -> rbuf, file, line);
858                 interface -> rbuf = (unsigned char *)0;
859         }
860         if (interface -> client)
861                 interface -> client = (struct client_state *)0;
862
863         if (interface -> shared_network)
864                 omapi_object_dereference ((omapi_object_t **)
865                                           &interface -> shared_network, MDL);
866
867         return ISC_R_SUCCESS;
868 }
869
870 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
871                                             const char *name, va_list ap)
872 {
873         struct interface_info *ip, *interface;
874         struct client_config *config;
875         struct client_state *client;
876         isc_result_t status;
877
878         if (h -> type != dhcp_type_interface)
879                 return ISC_R_INVALIDARG;
880         interface = (struct interface_info *)h;
881
882         /* If it's an update signal, see if the interface is dead right
883            now, or isn't known at all, and if that's the case, revive it. */
884         if (!strcmp (name, "update")) {
885                 for (ip = dummy_interfaces; ip; ip = ip -> next)
886                         if (ip == interface)
887                                 break;
888                 if (ip && dhcp_interface_startup_hook)
889                         return (*dhcp_interface_startup_hook) (ip);
890
891                 for (ip = interfaces; ip; ip = ip -> next)
892                         if (ip == interface)
893                                 break;
894                 if (!ip && dhcp_interface_startup_hook)
895                         return (*dhcp_interface_startup_hook) (ip);
896         }
897
898         /* Try to find some inner object that can take the value. */
899         if (h -> inner && h -> inner -> type -> get_value) {
900                 status = ((*(h -> inner -> type -> signal_handler))
901                           (h -> inner, name, ap));
902                 if (status == ISC_R_SUCCESS)
903                         return status;
904         }
905         return ISC_R_NOTFOUND;
906 }
907
908 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
909                                           omapi_object_t *id,
910                                           omapi_object_t *h)
911 {
912         struct interface_info *interface;
913         isc_result_t status;
914
915         if (h -> type != dhcp_type_interface)
916                 return ISC_R_INVALIDARG;
917         interface = (struct interface_info *)h;
918
919         /* Write out all the values. */
920
921         status = omapi_connection_put_name (c, "state");
922         if (status != ISC_R_SUCCESS)
923                 return status;
924         if (interface -> flags && INTERFACE_REQUESTED)
925             status = omapi_connection_put_string (c, "up");
926         else
927             status = omapi_connection_put_string (c, "down");
928         if (status != ISC_R_SUCCESS)
929                 return status;
930
931         /* Write out the inner object, if any. */
932         if (h -> inner && h -> inner -> type -> stuff_values) {
933                 status = ((*(h -> inner -> type -> stuff_values))
934                           (c, id, h -> inner));
935                 if (status == ISC_R_SUCCESS)
936                         return status;
937         }
938
939         return ISC_R_SUCCESS;
940 }
941
942 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
943                                     omapi_object_t *id,
944                                     omapi_object_t *ref)
945 {
946         omapi_value_t *tv = (omapi_value_t *)0;
947         isc_result_t status;
948         struct interface_info *interface;
949
950         if (!ref)
951                 return ISC_R_NOKEYS;
952
953         /* First see if we were sent a handle. */
954         status = omapi_get_value_str (ref, id, "handle", &tv);
955         if (status == ISC_R_SUCCESS) {
956                 status = omapi_handle_td_lookup (ip, tv -> value);
957
958                 omapi_value_dereference (&tv, MDL);
959                 if (status != ISC_R_SUCCESS)
960                         return status;
961
962                 /* Don't return the object if the type is wrong. */
963                 if ((*ip) -> type != dhcp_type_interface) {
964                         omapi_object_dereference (ip, MDL);
965                         return ISC_R_INVALIDARG;
966                 }
967         }
968
969         /* Now look for an interface name. */
970         status = omapi_get_value_str (ref, id, "name", &tv);
971         if (status == ISC_R_SUCCESS) {
972                 char *s;
973                 unsigned len;
974                 for (interface = interfaces; interface;
975                      interface = interface -> next) {
976                     s = memchr (interface -> name, 0, IFNAMSIZ);
977                     if (s)
978                             len = s - &interface -> name [0];
979                     else
980                             len = IFNAMSIZ;
981                     if ((tv -> value -> u.buffer.len == len &&
982                          !memcmp (interface -> name,
983                                   (char *)tv -> value -> u.buffer.value,
984                                   len)))
985                             break;
986                 }
987                 if (!interface) {
988                     for (interface = dummy_interfaces;
989                          interface; interface = interface -> next) {
990                             s = memchr (interface -> name, 0, IFNAMSIZ);
991                             if (s)
992                                     len = s - &interface -> name [0];
993                             else
994                                     len = IFNAMSIZ;
995                             if ((tv -> value -> u.buffer.len == len &&
996                                  !memcmp (interface -> name,
997                                           (char *)
998                                           tv -> value -> u.buffer.value,
999                                           len)))
1000                                     break;
1001                     }
1002                 }
1003
1004                 omapi_value_dereference (&tv, MDL);
1005                 if (*ip && *ip != (omapi_object_t *)interface) {
1006                         omapi_object_dereference (ip, MDL);
1007                         return ISC_R_KEYCONFLICT;
1008                 } else if (!interface) {
1009                         if (*ip)
1010                                 omapi_object_dereference (ip, MDL);
1011                         return ISC_R_NOTFOUND;
1012                 } else if (!*ip)
1013                         omapi_object_reference (ip,
1014                                                 (omapi_object_t *)interface,
1015                                                 MDL);
1016         }
1017
1018         /* If we get to here without finding an interface, no valid key was
1019            specified. */
1020         if (!*ip)
1021                 return ISC_R_NOKEYS;
1022         return ISC_R_SUCCESS;
1023 }
1024
1025 /* actually just go discover the interface */
1026 isc_result_t dhcp_interface_create (omapi_object_t **lp,
1027                                     omapi_object_t *id)
1028 {
1029         struct interface_info *hp;
1030         isc_result_t status;
1031         
1032         hp = (struct interface_info *)0;
1033         status = interface_allocate (&hp, MDL);
1034         if (status != ISC_R_SUCCESS)
1035                 return status;
1036         hp -> flags = INTERFACE_REQUESTED;
1037         status = interface_reference ((struct interface_info **)lp, hp, MDL);
1038         interface_dereference (&hp, MDL);
1039         return status;
1040 }
1041
1042 isc_result_t dhcp_interface_remove (omapi_object_t *lp,
1043                                     omapi_object_t *id)
1044 {
1045         struct interface_info *interface, *ip, *last;
1046
1047         interface = (struct interface_info *)lp;
1048
1049         /* remove from interfaces */
1050         last = 0;
1051         for (ip = interfaces; ip; ip = ip -> next) {
1052                 if (ip == interface) {
1053                         if (last) {
1054                                 interface_dereference (&last -> next, MDL);
1055                                 if (ip -> next)
1056                                         interface_reference (&last -> next,
1057                                                              ip -> next, MDL);
1058                         } else {
1059                                 interface_dereference (&interfaces, MDL);
1060                                 if (ip -> next)
1061                                         interface_reference (&interfaces,
1062                                                              ip -> next, MDL);
1063                         }
1064                         if (ip -> next)
1065                                 interface_dereference (&ip -> next, MDL);
1066                         break;
1067                 }
1068                 last = ip;
1069         }
1070         if (!ip)
1071                 return ISC_R_NOTFOUND;
1072
1073         /* add the interface to the dummy_interface list */
1074         if (dummy_interfaces) {
1075                 interface_reference (&interface -> next,
1076                                      dummy_interfaces, MDL);
1077                 interface_dereference (&dummy_interfaces, MDL);
1078         }
1079         interface_reference (&dummy_interfaces, interface, MDL);
1080
1081         /* do a DHCPRELEASE */
1082         if (dhcp_interface_shutdown_hook)
1083                 (*dhcp_interface_shutdown_hook) (interface);
1084
1085         /* remove the io object */
1086         omapi_unregister_io_object ((omapi_object_t *)interface);
1087
1088         if_deregister_send (interface);
1089         if_deregister_receive (interface);
1090
1091         return ISC_R_SUCCESS;
1092 }
1093
1094 void interface_stash (struct interface_info *tptr)
1095 {
1096         struct interface_info **vec;
1097         int delta;
1098
1099         /* If the registerer didn't assign an index, assign one now. */
1100         if (tptr -> index == -1) {
1101                 tptr -> index = interface_count++;
1102                 while (tptr -> index < interface_max &&
1103                        interface_vector [tptr -> index])
1104                         tptr -> index = interface_count++;
1105         }
1106
1107         if (interface_max <= tptr -> index) {
1108                 delta = tptr -> index - interface_max + 10;
1109                 vec = dmalloc ((interface_max + delta) *
1110                                sizeof (struct interface_info *), MDL);
1111                 if (!vec)
1112                         return;
1113                 memset (&vec [interface_max], 0,
1114                         (sizeof (struct interface_info *)) * delta);
1115                 interface_max += delta;
1116                 if (interface_vector) {
1117                     memcpy (vec, interface_vector,
1118                             (interface_count *
1119                              sizeof (struct interface_info *)));
1120                     dfree (interface_vector, MDL);
1121                 }
1122                 interface_vector = vec;
1123         }
1124         interface_reference (&interface_vector [tptr -> index], tptr, MDL);
1125         if (tptr -> index >= interface_count)
1126                 interface_count = tptr -> index + 1;
1127 #if defined (TRACING)
1128         trace_interface_register (interface_trace, tptr);
1129 #endif
1130 }
1131
1132 void interface_snorf (struct interface_info *tmp, int ir)
1133 {
1134         tmp -> circuit_id = (u_int8_t *)tmp -> name;
1135         tmp -> circuit_id_len = strlen (tmp -> name);
1136         tmp -> remote_id = 0;
1137         tmp -> remote_id_len = 0;
1138         tmp -> flags = ir;
1139         if (interfaces) {
1140                 interface_reference (&tmp -> next,
1141                                      interfaces, MDL);
1142                 interface_dereference (&interfaces, MDL);
1143         }
1144         interface_reference (&interfaces, tmp, MDL);
1145 }