]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/isc-dhcp/common/dispatch.c
This commit was generated by cvs2svn to compensate for changes in r54359,
[FreeBSD/FreeBSD.git] / contrib / isc-dhcp / common / dispatch.c
1 /* dispatch.c
2
3    Network input dispatcher... */
4
5 /*
6  * Copyright (c) 1995, 1996, 1997, 1998, 1999
7  * The Internet Software Consortium.   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 <mellon@fugue.com> in cooperation with Vixie
38  * Enterprises.  To learn more about the Internet Software Consortium,
39  * see ``http://www.vix.com/isc''.  To learn more about Vixie
40  * Enterprises, see ``http://www.vix.com''.
41  */
42
43 #ifndef lint
44 static char copyright[] =
45 "$Id: dispatch.c,v 1.47.2.14 1999/03/29 22:16:36 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium.  All rights reserved.\n";
46 #endif /* not lint */
47
48 #include "dhcpd.h"
49 #include <sys/ioctl.h>
50
51 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
52 struct protocol *protocols;
53 struct timeout *timeouts;
54 static struct timeout *free_timeouts;
55 static int interfaces_invalidated;
56 void (*bootp_packet_handler) PROTO ((struct interface_info *,
57                                      struct dhcp_packet *, int, unsigned int,
58                                      struct iaddr, struct hardware *));
59
60 int quiet_interface_discovery;
61
62 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
63    For each interface that's of type INET and not the loopback interface,
64    register that interface with the network I/O software, figure out what
65    subnet it's on, and add it to the list of interfaces. */
66
67 void discover_interfaces (state)
68         int state;
69 {
70         struct interface_info *tmp;
71         struct interface_info *last, *next;
72         char buf [8192];
73         struct ifconf ic;
74         struct ifreq ifr;
75         int i;
76         int sock;
77         struct subnet *subnet;
78         struct shared_network *share;
79         struct sockaddr_in foo;
80         int ir;
81         struct ifreq *tif;
82 #ifdef ALIAS_NAMES_PERMUTED
83         char *s;
84 #endif
85
86         /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
87         if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
88                 error ("Can't create addrlist socket");
89
90         /* Get the interface configuration information... */
91         ic.ifc_len = sizeof buf;
92         ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
93         i = ioctl(sock, SIOCGIFCONF, &ic);
94
95         if (i < 0)
96                 error ("ioctl: SIOCGIFCONF: %m");
97
98         /* If we already have a list of interfaces, and we're running as
99            a DHCP server, the interfaces were requested. */
100         if (interfaces && (state == DISCOVER_SERVER ||
101                            state == DISCOVER_RELAY ||
102                            state == DISCOVER_REQUESTED))
103                 ir = 0;
104         else if (state == DISCOVER_UNCONFIGURED)
105                 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
106         else
107                 ir = INTERFACE_REQUESTED;
108
109         /* Cycle through the list of interfaces looking for IP addresses. */
110         for (i = 0; i < ic.ifc_len;) {
111                 struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
112 #ifdef HAVE_SA_LEN
113                 if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr))
114                         i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
115                 else
116 #endif
117                         i += sizeof *ifp;
118
119 #ifdef ALIAS_NAMES_PERMUTED
120                 if ((s = strrchr (ifp -> ifr_name, ':'))) {
121                         *s = 0;
122                 }
123 #endif
124
125 #ifdef SKIP_DUMMY_INTERFACES
126                 if (!strncmp (ifp -> ifr_name, "dummy", 5))
127                         continue;
128 #endif
129
130
131                 /* See if this is the sort of interface we want to
132                    deal with. */
133                 strcpy (ifr.ifr_name, ifp -> ifr_name);
134                 if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
135                         error ("Can't get interface flags for %s: %m",
136                                ifr.ifr_name);
137
138                 /* Skip loopback, point-to-point and down interfaces,
139                    except don't skip down interfaces if we're trying to
140                    get a list of configurable interfaces. */
141                 if ((ifr.ifr_flags & IFF_LOOPBACK) ||
142 #ifdef HAVE_IFF_POINTOPOINT
143                     (ifr.ifr_flags & IFF_POINTOPOINT) ||
144 #endif
145                     (!(ifr.ifr_flags & IFF_UP) &&
146                      state != DISCOVER_UNCONFIGURED))
147                         continue;
148                 
149                 /* See if we've seen an interface that matches this one. */
150                 for (tmp = interfaces; tmp; tmp = tmp -> next)
151                         if (!strcmp (tmp -> name, ifp -> ifr_name))
152                                 break;
153
154                 /* If there isn't already an interface by this name,
155                    allocate one. */
156                 if (!tmp) {
157                         tmp = ((struct interface_info *)
158                                dmalloc (sizeof *tmp, "discover_interfaces"));
159                         if (!tmp)
160                                 error ("Insufficient memory to %s %s",
161                                        "record interface", ifp -> ifr_name);
162                         strcpy (tmp -> name, ifp -> ifr_name);
163                         tmp -> next = interfaces;
164                         tmp -> flags = ir;
165                         interfaces = tmp;
166                 }
167
168                 /* If we have the capability, extract link information
169                    and record it in a linked list. */
170 #ifdef HAVE_AF_LINK
171                 if (ifp -> ifr_addr.sa_family == AF_LINK) {
172                         struct sockaddr_dl *foo = ((struct sockaddr_dl *)
173                                                    (&ifp -> ifr_addr));
174                         tmp -> hw_address.hlen = foo -> sdl_alen;
175                         tmp -> hw_address.htype = HTYPE_ETHER; /* XXX */
176                         memcpy (tmp -> hw_address.haddr,
177                                 LLADDR (foo), foo -> sdl_alen);
178                 } else
179 #endif /* AF_LINK */
180
181                 if (ifp -> ifr_addr.sa_family == AF_INET) {
182                         struct iaddr addr;
183
184                         /* Get a pointer to the address... */
185                         memcpy (&foo, &ifp -> ifr_addr,
186                                 sizeof ifp -> ifr_addr);
187
188                         /* We don't want the loopback interface. */
189                         if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK))
190                                 continue;
191
192
193                         /* If this is the first real IP address we've
194                            found, keep a pointer to ifreq structure in
195                            which we found it. */
196                         if (!tmp -> ifp) {
197 #ifdef HAVE_SA_LEN
198                                 int len = ((sizeof ifp -> ifr_name) +
199                                            ifp -> ifr_addr.sa_len);
200 #else
201                                 int len = sizeof *ifp;
202 #endif
203                                 tif = (struct ifreq *)malloc (len);
204                                 if (!tif)
205                                         error ("no space to remember ifp.");
206                                 memcpy (tif, ifp, len);
207                                 tmp -> ifp = tif;
208                                 tmp -> primary_address = foo.sin_addr;
209                         }
210
211                         /* Grab the address... */
212                         addr.len = 4;
213                         memcpy (addr.iabuf, &foo.sin_addr.s_addr,
214                                 addr.len);
215
216                         /* If there's a registered subnet for this address,
217                            connect it together... */
218                         if ((subnet = find_subnet (addr))) {
219                                 /* If this interface has multiple aliases
220                                    on the same subnet, ignore all but the
221                                    first we encounter. */
222                                 if (!subnet -> interface) {
223                                         subnet -> interface = tmp;
224                                         subnet -> interface_address = addr;
225                                 } else if (subnet -> interface != tmp) {
226                                         warn ("Multiple %s %s: %s %s", 
227                                               "interfaces match the",
228                                               "same subnet",
229                                               subnet -> interface -> name,
230                                               tmp -> name);
231                                 }
232                                 share = subnet -> shared_network;
233                                 if (tmp -> shared_network &&
234                                     tmp -> shared_network != share) {
235                                         warn ("Interface %s matches %s",
236                                               tmp -> name,
237                                               "multiple shared networks");
238                                 } else {
239                                         tmp -> shared_network = share;
240                                 }
241
242                                 if (!share -> interface) {
243                                         share -> interface = tmp;
244                                 } else if (share -> interface != tmp) {
245                                         warn ("Multiple %s %s: %s %s", 
246                                               "interfaces match the",
247                                               "same shared network",
248                                               share -> interface -> name,
249                                               tmp -> name);
250                                 }
251                         }
252                 }
253         }
254
255 #if defined (LINUX_SLASHPROC_DISCOVERY)
256         /* On Linux, interfaces that don't have IP addresses don't show up
257            in the SIOCGIFCONF syscall.   We got away with this prior to
258            Linux 2.1 because we would give each interface an IP address of
259            0.0.0.0 before trying to boot, but that doesn't work after 2.1
260            because we're using LPF, because we can't configure interfaces
261            with IP addresses of 0.0.0.0 anymore (grumble).   This only
262            matters for the DHCP client, of course - the relay agent and
263            server should only care about interfaces that are configured
264            with IP addresses anyway.
265
266            The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
267            that, when read, prints a human readable network status.   We
268            extract the names of the network devices by skipping the first
269            two lines (which are header) and then parsing off everything
270            up to the colon in each subsequent line - these lines start
271            with the interface name, then a colon, then a bunch of
272            statistics.   Yes, Virgina, this is a kludge, but you work
273            with what you have. */
274
275         if (state == DISCOVER_UNCONFIGURED) {
276                 FILE *proc_dev;
277                 char buffer [256];
278                 int skip = 2;
279
280                 proc_dev = fopen (PROCDEV_DEVICE, "r");
281                 if (!proc_dev)
282                         error ("%s: %m", PROCDEV_DEVICE);
283
284                 while (fgets (buffer, sizeof buffer, proc_dev)) {
285                         char *name = buffer;
286                         char *sep;
287
288                         /* Skip the first two blocks, which are header
289                            lines. */
290                         if (skip) {
291                                 --skip;
292                                 continue;
293                         }
294
295                         sep = strrchr (buffer, ':');
296                         if (sep)
297                                 *sep = '\0';
298                         while (*name == ' ')
299                                 name++;
300
301                         /* See if we've seen an interface that matches
302                            this one. */
303                         for (tmp = interfaces; tmp; tmp = tmp -> next)
304                                 if (!strcmp (tmp -> name, name))
305                                         break;
306
307                         /* If we found one, nothing more to do.. */
308                         if (tmp)
309                                 continue;
310
311                         /* Otherwise, allocate one. */
312                         tmp = ((struct interface_info *)
313                                dmalloc (sizeof *tmp, "discover_interfaces"));
314                         if (!tmp)
315                                 error ("Insufficient memory to %s %s",
316                                        "record interface", name);
317                         memset (tmp, 0, sizeof *tmp);
318                         strcpy (tmp -> name, name);
319
320                         tmp -> flags = ir;
321                         tmp -> next = interfaces;
322                         interfaces = tmp;
323                 }
324                 fclose (proc_dev);
325         }
326 #endif
327
328         /* Now cycle through all the interfaces we found, looking for
329            hardware addresses. */
330 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
331         for (tmp = interfaces; tmp; tmp = tmp -> next) {
332                 struct ifreq ifr;
333                 struct sockaddr sa;
334                 int b, sk;
335                 
336                 if (!tmp -> ifp) {
337                         /* Make up an ifreq structure. */
338                         tif = (struct ifreq *)malloc (sizeof (struct ifreq));
339                         if (!tif)
340                                 error ("no space to remember ifp.");
341                         memset (tif, 0, sizeof (struct ifreq));
342                         strcpy (tif -> ifr_name, tmp -> name);
343                         tmp -> ifp = tif;
344                 }
345
346                 /* Read the hardware address from this interface. */
347                 ifr = *tmp -> ifp;
348                 if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
349                         continue;
350                 
351                 sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
352                 
353                 switch (sa.sa_family) {
354 #ifdef HAVE_ARPHRD_TUNNEL
355                       case ARPHRD_TUNNEL:
356                         /* ignore tunnel interfaces. */
357 #endif
358 #ifdef HAVE_ARPHRD_ROSE
359                       case ARPHRD_ROSE:
360 #endif
361 #ifdef HAVE_ARPHRD_LOOPBACK
362                       case ARPHRD_LOOPBACK:
363                         /* ignore loopback interface */
364                         break;
365 #endif
366
367                       case ARPHRD_ETHER:
368                         tmp -> hw_address.hlen = 6;
369                         tmp -> hw_address.htype = ARPHRD_ETHER;
370                         memcpy (tmp -> hw_address.haddr, sa.sa_data, 6);
371                         break;
372
373 #ifndef HAVE_ARPHRD_IEEE802
374 # define ARPHRD_IEEE802 HTYPE_IEEE802
375 #endif
376                       case ARPHRD_IEEE802:
377                         tmp -> hw_address.hlen = 6;
378                         tmp -> hw_address.htype = ARPHRD_IEEE802;
379                         memcpy (tmp -> hw_address.haddr, sa.sa_data, 6);
380                         break;
381
382 #ifndef HAVE_ARPHRD_FDDI
383 # define ARPHRD_FDDI HTYPE_FDDI
384 #endif
385                       case ARPHRD_FDDI:
386                         tmp -> hw_address.hlen = 16;
387                         tmp -> hw_address.htype = HTYPE_FDDI; /* XXX */
388                         memcpy (tmp -> hw_address.haddr, sa.sa_data, 16);
389                         break;
390
391 #ifdef HAVE_ARPHRD_METRICOM
392                       case ARPHRD_METRICOM:
393                         tmp -> hw_address.hlen = 6;
394                         tmp -> hw_address.htype = ARPHRD_METRICOM;
395                         memcpy (tmp -> hw_address.haddr, sa.sa_data, 6);
396                         break;
397 #endif
398
399 #ifdef HAVE_ARPHRD_AX25
400                       case ARPHRD_AX25:
401                         tmp -> hw_address.hlen = 6;
402                         tmp -> hw_address.htype = ARPHRD_AX25;
403                         memcpy (tmp -> hw_address.haddr, sa.sa_data, 6);
404                         break;
405 #endif
406
407 #ifdef HAVE_ARPHRD_NETROM
408                       case ARPHRD_NETROM:
409                         tmp -> hw_address.hlen = 6;
410                         tmp -> hw_address.htype = ARPHRD_NETROM;
411                         memcpy (tmp -> hw_address.haddr, sa.sa_data, 6);
412                         break;
413 #endif
414
415                       default:
416                         warn ("%s: unknown hardware address type %d",
417                                ifr.ifr_name, sa.sa_family);
418                         break;
419                 }
420         }
421 #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
422
423         /* If we're just trying to get a list of interfaces that we might
424            be able to configure, we can quit now. */
425         if (state == DISCOVER_UNCONFIGURED)
426                 return;
427
428         /* Weed out the interfaces that did not have IP addresses. */
429         last = (struct interface_info *)0;
430         for (tmp = interfaces; tmp; tmp = next) {
431                 next = tmp -> next;
432                 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
433                     state == DISCOVER_REQUESTED)
434                         tmp -> flags &= ~(INTERFACE_AUTOMATIC |
435                                           INTERFACE_REQUESTED);
436                 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
437                         if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
438                                 error ("%s: not found", tmp -> name);
439                         if (!last)
440                                 interfaces = interfaces -> next;
441                         else
442                                 last -> next = tmp -> next;
443
444                         /* Remember the interface in case we need to know
445                            about it later. */
446                         tmp -> next = dummy_interfaces;
447                         dummy_interfaces = tmp;
448                         continue;
449                 }
450                 last = tmp;
451
452                 memcpy (&foo, &tmp -> ifp -> ifr_addr,
453                         sizeof tmp -> ifp -> ifr_addr);
454
455                 /* We must have a subnet declaration for each interface. */
456                 if (!tmp -> shared_network && (state == DISCOVER_SERVER)) {
457                         warn ("No subnet declaration for %s (%s).",
458                               tmp -> name, inet_ntoa (foo.sin_addr));
459                         warn ("Please write a subnet declaration for the %s",
460                               "network segment to");
461                         error ("which interface %s is attached.", tmp -> name);
462                 }
463
464                 /* Find subnets that don't have valid interface
465                    addresses... */
466                 for (subnet = (tmp -> shared_network
467                                ? tmp -> shared_network -> subnets
468                                : (struct subnet *)0);
469                      subnet; subnet = subnet -> next_sibling) {
470                         if (!subnet -> interface_address.len) {
471                                 /* Set the interface address for this subnet
472                                    to the first address we found. */
473                                 subnet -> interface_address.len = 4;
474                                 memcpy (subnet -> interface_address.iabuf,
475                                         &foo.sin_addr.s_addr, 4);
476                         }
477                 }
478
479                 /* Register the interface... */
480                 if_register_receive (tmp);
481                 if_register_send (tmp);
482         }
483
484         /* Now register all the remaining interfaces as protocols. */
485         for (tmp = interfaces; tmp; tmp = tmp -> next)
486                 add_protocol (tmp -> name, tmp -> rfdesc, got_one, tmp);
487
488         close (sock);
489
490         maybe_setup_fallback ();
491 }
492
493 struct interface_info *setup_fallback ()
494 {
495         fallback_interface =
496                 ((struct interface_info *)
497                  dmalloc (sizeof *fallback_interface, "discover_interfaces"));
498         if (!fallback_interface)
499                 error ("Insufficient memory to record fallback interface.");
500         memset (fallback_interface, 0, sizeof *fallback_interface);
501         strcpy (fallback_interface -> name, "fallback");
502         fallback_interface -> shared_network =
503                 new_shared_network ("parse_statement");
504         if (!fallback_interface -> shared_network)
505                 error ("No memory for shared subnet");
506         memset (fallback_interface -> shared_network, 0,
507                 sizeof (struct shared_network));
508         fallback_interface -> shared_network -> name = "fallback-net";
509         return fallback_interface;
510 }
511
512 void reinitialize_interfaces ()
513 {
514         struct interface_info *ip;
515
516         for (ip = interfaces; ip; ip = ip -> next) {
517                 if_reinitialize_receive (ip);
518                 if_reinitialize_send (ip);
519         }
520
521         if (fallback_interface)
522                 if_reinitialize_send (fallback_interface);
523
524         interfaces_invalidated = 1;
525 }
526
527 #ifdef USE_POLL
528 /* Wait for packets to come in using poll().  When a packet comes in,
529    call receive_packet to receive the packet and possibly strip hardware
530    addressing information from it, and then call through the
531    bootp_packet_handler hook to try to do something with it. */
532
533 void dispatch ()
534 {
535         struct protocol *l;
536         int nfds = 0;
537         struct pollfd *fds;
538         int count;
539         int i;
540         int to_msec;
541
542         nfds = 0;
543         for (l = protocols; l; l = l -> next) {
544                 ++nfds;
545         }
546         fds = (struct pollfd *)malloc ((nfds) * sizeof (struct pollfd));
547         if (!fds)
548                 error ("Can't allocate poll structures.");
549
550         do {
551                 /* Call any expired timeouts, and then if there's
552                    still a timeout registered, time out the select
553                    call then. */
554               another:
555                 if (timeouts) {
556                         struct timeout *t;
557                         if (timeouts -> when <= cur_time) {
558                                 t = timeouts;
559                                 timeouts = timeouts -> next;
560                                 (*(t -> func)) (t -> what);
561                                 t -> next = free_timeouts;
562                                 free_timeouts = t;
563                                 goto another;
564                         }
565                         /* Figure timeout in milliseconds, and check for
566                            potential overflow.   We assume that integers
567                            are 32 bits, which is harmless if they're 64
568                            bits - we'll just get extra timeouts in that
569                            case.    Lease times would have to be quite
570                            long in order for a 32-bit integer to overflow,
571                            anyway. */
572                         to_msec = timeouts -> when - cur_time;
573                         if (to_msec > 2147483)
574                                 to_msec = 2147483;
575                         to_msec *= 1000;
576                 } else
577                         to_msec = -1;
578
579                 /* Set up the descriptors to be polled. */
580                 i = 0;
581                 for (l = protocols; l; l = l -> next) {
582                         fds [i].fd = l -> fd;
583                         fds [i].events = POLLIN;
584                         fds [i].revents = 0;
585                         ++i;
586                 }
587
588                 /* Wait for a packet or a timeout... XXX */
589                 count = poll (fds, nfds, to_msec);
590
591                 /* Get the current time... */
592                 GET_TIME (&cur_time);
593
594                 /* Not likely to be transitory... */
595                 if (count < 0) {
596                         if (errno == EAGAIN || errno == EINTR)
597                                 continue;
598                         else
599                                 error ("poll: %m");
600                 }
601
602                 i = 0;
603                 for (l = protocols; l; l = l -> next) {
604                         if ((fds [i].revents & POLLIN)) {
605                                 fds [i].revents = 0;
606                                 if (l -> handler)
607                                         (*(l -> handler)) (l);
608                                 if (interfaces_invalidated)
609                                         break;
610                         }
611                         ++i;
612                 }
613                 interfaces_invalidated = 0;
614         } while (1);
615 }
616 #else
617 /* Wait for packets to come in using select().   When one does, call
618    receive_packet to receive the packet and possibly strip hardware
619    addressing information from it, and then call through the
620    bootp_packet_handler hook to try to do something with it. */
621
622 void dispatch ()
623 {
624         fd_set r, w, x;
625         struct protocol *l;
626         int max = 0;
627         int count;
628         struct timeval tv, *tvp;
629
630         FD_ZERO (&w);
631         FD_ZERO (&x);
632
633         do {
634                 /* Call any expired timeouts, and then if there's
635                    still a timeout registered, time out the select
636                    call then. */
637               another:
638                 if (timeouts) {
639                         struct timeout *t;
640                         if (timeouts -> when <= cur_time) {
641                                 t = timeouts;
642                                 timeouts = timeouts -> next;
643                                 (*(t -> func)) (t -> what);
644                                 t -> next = free_timeouts;
645                                 free_timeouts = t;
646                                 goto another;
647                         }
648                         tv.tv_sec = timeouts -> when - cur_time;
649                         tv.tv_usec = 0;
650                         tvp = &tv;
651                 } else
652                         tvp = (struct timeval *)0;
653
654                 /* Set up the read mask. */
655                 FD_ZERO (&r);
656
657                 for (l = protocols; l; l = l -> next) {
658                         FD_SET (l -> fd, &r);
659                         if (l -> fd > max)
660                                 max = l -> fd;
661                 }
662
663                 /* Wait for a packet or a timeout... XXX */
664                 count = select (max + 1, &r, &w, &x, tvp);
665
666                 /* Get the current time... */
667                 GET_TIME (&cur_time);
668
669                 /* Not likely to be transitory... */
670                 if (count < 0)
671                         error ("select: %m");
672
673                 for (l = protocols; l; l = l -> next) {
674                         if (!FD_ISSET (l -> fd, &r))
675                                 continue;
676                         if (l -> handler)
677                                 (*(l -> handler)) (l);
678                         if (interfaces_invalidated)
679                                 break;
680                 }
681                 interfaces_invalidated = 0;
682         } while (1);
683 }
684 #endif /* USE_POLL */
685
686 void got_one (l)
687         struct protocol *l;
688 {
689         struct sockaddr_in from;
690         struct hardware hfrom;
691         struct iaddr ifrom;
692         int result;
693         union {
694                 unsigned char packbuf [4095]; /* Packet input buffer.
695                                                  Must be as large as largest
696                                                  possible MTU. */
697                 struct dhcp_packet packet;
698         } u;
699         struct interface_info *ip = l -> local;
700
701         if ((result =
702              receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
703                 warn ("receive_packet failed on %s: %m", ip -> name);
704                 return;
705         }
706         if (result == 0)
707                 return;
708
709         if (bootp_packet_handler) {
710                 ifrom.len = 4;
711                 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
712
713                 (*bootp_packet_handler) (ip, &u.packet, result,
714                                          from.sin_port, ifrom, &hfrom);
715         }
716 }
717
718 int locate_network (packet)
719         struct packet *packet;
720 {
721         struct iaddr ia;
722
723         /* If this came through a gateway, find the corresponding subnet... */
724         if (packet -> raw -> giaddr.s_addr) {
725                 struct subnet *subnet;
726                 ia.len = 4;
727                 memcpy (ia.iabuf, &packet -> raw -> giaddr, 4);
728                 subnet = find_subnet (ia);
729                 if (subnet)
730                         packet -> shared_network = subnet -> shared_network;
731                 else
732                         packet -> shared_network = (struct shared_network *)0;
733         } else {
734                 packet -> shared_network =
735                         packet -> interface -> shared_network;
736         }
737         if (packet -> shared_network)
738                 return 1;
739         return 0;
740 }
741
742 void add_timeout (when, where, what)
743         TIME when;
744         void (*where) PROTO ((void *));
745         void *what;
746 {
747         struct timeout *t, *q;
748
749         /* See if this timeout supersedes an existing timeout. */
750         t = (struct timeout *)0;
751         for (q = timeouts; q; q = q -> next) {
752                 if (q -> func == where && q -> what == what) {
753                         if (t)
754                                 t -> next = q -> next;
755                         else
756                                 timeouts = q -> next;
757                         break;
758                 }
759                 t = q;
760         }
761
762         /* If we didn't supersede a timeout, allocate a timeout
763            structure now. */
764         if (!q) {
765                 if (free_timeouts) {
766                         q = free_timeouts;
767                         free_timeouts = q -> next;
768                         q -> func = where;
769                         q -> what = what;
770                 } else {
771                         q = (struct timeout *)malloc (sizeof (struct timeout));
772                         if (!q)
773                                 error ("Can't allocate timeout structure!");
774                         q -> func = where;
775                         q -> what = what;
776                 }
777         }
778
779         q -> when = when;
780
781         /* Now sort this timeout into the timeout list. */
782
783         /* Beginning of list? */
784         if (!timeouts || timeouts -> when > q -> when) {
785                 q -> next = timeouts;
786                 timeouts = q;
787                 return;
788         }
789
790         /* Middle of list? */
791         for (t = timeouts; t -> next; t = t -> next) {
792                 if (t -> next -> when > q -> when) {
793                         q -> next = t -> next;
794                         t -> next = q;
795                         return;
796                 }
797         }
798
799         /* End of list. */
800         t -> next = q;
801         q -> next = (struct timeout *)0;
802 }
803
804 void cancel_timeout (where, what)
805         void (*where) PROTO ((void *));
806         void *what;
807 {
808         struct timeout *t, *q;
809
810         /* Look for this timeout on the list, and unlink it if we find it. */
811         t = (struct timeout *)0;
812         for (q = timeouts; q; q = q -> next) {
813                 if (q -> func == where && q -> what == what) {
814                         if (t)
815                                 t -> next = q -> next;
816                         else
817                                 timeouts = q -> next;
818                         break;
819                 }
820                 t = q;
821         }
822
823         /* If we found the timeout, put it on the free list. */
824         if (q) {
825                 q -> next = free_timeouts;
826                 free_timeouts = q;
827         }
828 }
829
830 /* Add a protocol to the list of protocols... */
831 void add_protocol (name, fd, handler, local)
832         char *name;
833         int fd;
834         void (*handler) PROTO ((struct protocol *));
835         void *local;
836 {
837         struct protocol *p;
838
839         p = (struct protocol *)malloc (sizeof *p);
840         if (!p)
841                 error ("can't allocate protocol struct for %s", name);
842
843         p -> fd = fd;
844         p -> handler = handler;
845         p -> local = local;
846
847         p -> next = protocols;
848         protocols = p;
849 }
850
851 void remove_protocol (proto)
852         struct protocol *proto;
853 {
854         struct protocol *p, *next, *prev;
855
856         prev = (struct protocol *)0;
857         for (p = protocols; p; p = next) {
858                 next = p -> next;
859                 if (p == proto) {
860                         if (prev)
861                                 prev -> next = p -> next;
862                         else
863                                 protocols = p -> next;
864                         free (p);
865                 }
866         }
867 }