]> git.ipfire.org Git - thirdparty/dhcp.git/blame - common/discover.c
Change names of error functions to be more consistent.
[thirdparty/dhcp.git] / common / discover.c
CommitLineData
fa226d8f
TL
1/* dispatch.c
2
3 Network input dispatcher... */
4
5/*
d2bc90bd 6 * Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium.
fa226d8f
TL
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 <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
44static char copyright[] =
8ae2d595 45"$Id: discover.c,v 1.4 1999/02/24 17:56:44 mellon Exp $ Copyright (c) 1995, 1996, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
fa226d8f
TL
46#endif /* not lint */
47
48#include "dhcpd.h"
49#include <sys/ioctl.h>
50
d2bc90bd 51struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
fa226d8f
TL
52extern int interfaces_invalidated;
53int quiet_interface_discovery;
54
55void (*bootp_packet_handler) PROTO ((struct interface_info *,
56 struct dhcp_packet *, int, unsigned int,
57 struct iaddr, struct hardware *));
58
fa226d8f
TL
59/* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
60 For each interface that's of type INET and not the loopback interface,
61 register that interface with the network I/O software, figure out what
62 subnet it's on, and add it to the list of interfaces. */
63
64void discover_interfaces (state)
65 int state;
66{
67 struct interface_info *tmp;
68 struct interface_info *last, *next;
69 char buf [8192];
70 struct ifconf ic;
71 struct ifreq ifr;
72 int i;
73 int sock;
74 int address_count = 0;
75 struct subnet *subnet;
76 struct shared_network *share;
77 struct sockaddr_in foo;
78 int ir;
d2bc90bd 79 struct ifreq *tif;
fa226d8f
TL
80#ifdef ALIAS_NAMES_PERMUTED
81 char *s;
82#endif
fa226d8f
TL
83
84 /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */
85 if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
8ae2d595 86 log_fatal ("Can't create addrlist socket");
fa226d8f
TL
87
88 /* Get the interface configuration information... */
89 ic.ifc_len = sizeof buf;
90 ic.ifc_ifcu.ifcu_buf = (caddr_t)buf;
91 i = ioctl(sock, SIOCGIFCONF, &ic);
92
93 if (i < 0)
8ae2d595 94 log_fatal ("ioctl: SIOCGIFCONF: %m");
fa226d8f
TL
95
96 /* If we already have a list of interfaces, and we're running as
97 a DHCP server, the interfaces were requested. */
98 if (interfaces && (state == DISCOVER_SERVER ||
99 state == DISCOVER_RELAY ||
100 state == DISCOVER_REQUESTED))
101 ir = 0;
102 else if (state == DISCOVER_UNCONFIGURED)
103 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
104 else
105 ir = INTERFACE_REQUESTED;
106
d2bc90bd 107 /* Cycle through the list of interfaces looking for IP addresses. */
fa226d8f
TL
108 for (i = 0; i < ic.ifc_len;) {
109 struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i);
110#ifdef HAVE_SA_LEN
d2bc90bd 111 if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr))
fa226d8f
TL
112 i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len;
113 else
114#endif
115 i += sizeof *ifp;
116
117#ifdef ALIAS_NAMES_PERMUTED
118 if ((s = strrchr (ifp -> ifr_name, ':'))) {
119 *s = 0;
120 }
121#endif
122
123#ifdef SKIP_DUMMY_INTERFACES
124 if (!strncmp (ifp -> ifr_name, "dummy", 5))
125 continue;
126#endif
127
128
129 /* See if this is the sort of interface we want to
130 deal with. */
131 strcpy (ifr.ifr_name, ifp -> ifr_name);
132 if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0)
8ae2d595 133 log_fatal ("Can't get interface flags for %s: %m",
fa226d8f
TL
134 ifr.ifr_name);
135
5c0ba9a1
TL
136 /* See if we've seen an interface that matches this one. */
137 for (tmp = interfaces; tmp; tmp = tmp -> next)
138 if (!strcmp (tmp -> name, ifp -> ifr_name))
139 break;
140
fa226d8f
TL
141 /* Skip loopback, point-to-point and down interfaces,
142 except don't skip down interfaces if we're trying to
143 get a list of configurable interfaces. */
5c0ba9a1 144 if ((((ifr.ifr_flags & IFF_LOOPBACK) ||
fa226d8f 145#ifdef IFF_POINTOPOINT
5c0ba9a1
TL
146 (ifr.ifr_flags & IFF_POINTOPOINT))
147 && !tmp) ||
fa226d8f
TL
148#endif
149 (!(ifr.ifr_flags & IFF_UP) &&
150 state != DISCOVER_UNCONFIGURED))
151 continue;
152
fa226d8f
TL
153 /* If there isn't already an interface by this name,
154 allocate one. */
155 if (!tmp) {
156 tmp = ((struct interface_info *)
157 dmalloc (sizeof *tmp, "discover_interfaces"));
158 if (!tmp)
8ae2d595 159 log_fatal ("Insufficient memory to %s %s",
fa226d8f
TL
160 "record interface", ifp -> ifr_name);
161 strcpy (tmp -> name, ifp -> ifr_name);
162 tmp -> circuit_id = (u_int8_t *)tmp -> name;
163 tmp -> circuit_id_len = strlen (tmp -> name);
164 tmp -> remote_id = 0;
165 tmp -> remote_id_len = 0;
166 tmp -> next = interfaces;
167 tmp -> flags = ir;
168 interfaces = tmp;
169 }
170
171 /* If we have the capability, extract link information
172 and record it in a linked list. */
173#ifdef AF_LINK
174 if (ifp -> ifr_addr.sa_family == AF_LINK) {
175 struct sockaddr_dl *foo = ((struct sockaddr_dl *)
176 (&ifp -> ifr_addr));
177#if defined (HAVE_SIN_LEN)
178 tmp -> hw_address.hlen = foo -> sdl_alen;
179#else
180 tmp -> hw_address.hlen = 6; /* XXX!!! */
181#endif
182 tmp -> hw_address.htype = HTYPE_ETHER; /* XXX */
183 memcpy (tmp -> hw_address.haddr,
184 LLADDR (foo), tmp -> hw_address.hlen);
185 } else
186#endif /* AF_LINK */
187
188 if (ifp -> ifr_addr.sa_family == AF_INET) {
189 struct iaddr addr;
190
fa226d8f
TL
191 /* Get a pointer to the address... */
192 memcpy (&foo, &ifp -> ifr_addr,
193 sizeof ifp -> ifr_addr);
194
195 /* We don't want the loopback interface. */
196 if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK))
197 continue;
198
199
200 /* If this is the first real IP address we've
201 found, keep a pointer to ifreq structure in
202 which we found it. */
203 if (!tmp -> ifp) {
fa226d8f
TL
204#ifdef HAVE_SA_LEN
205 int len = ((sizeof ifp -> ifr_name) +
206 ifp -> ifr_addr.sa_len);
207#else
208 int len = sizeof *ifp;
209#endif
210 tif = (struct ifreq *)malloc (len);
211 if (!tif)
8ae2d595 212 log_fatal ("no space to remember ifp.");
fa226d8f
TL
213 memcpy (tif, ifp, len);
214 tmp -> ifp = tif;
215 tmp -> primary_address = foo.sin_addr;
216 }
217
218 /* Grab the address... */
219 addr.len = 4;
220 memcpy (addr.iabuf, &foo.sin_addr.s_addr,
221 addr.len);
222
223 /* If there's a registered subnet for this address,
224 connect it together... */
225 if ((subnet = find_subnet (addr))) {
226 /* If this interface has multiple aliases
227 on the same subnet, ignore all but the
228 first we encounter. */
229 if (!subnet -> interface) {
230 subnet -> interface = tmp;
231 subnet -> interface_address = addr;
232 } else if (subnet -> interface != tmp) {
8ae2d595 233 log_error ("Multiple %s %s: %s %s",
fa226d8f
TL
234 "interfaces match the",
235 "same subnet",
236 subnet -> interface -> name,
237 tmp -> name);
238 }
239 share = subnet -> shared_network;
240 if (tmp -> shared_network &&
241 tmp -> shared_network != share) {
8ae2d595 242 log_error ("Interface %s matches %s",
fa226d8f
TL
243 tmp -> name,
244 "multiple shared networks");
245 } else {
246 tmp -> shared_network = share;
247 }
248
249 if (!share -> interface) {
250 share -> interface = tmp;
251 } else if (share -> interface != tmp) {
8ae2d595 252 log_error ("Multiple %s %s: %s %s",
fa226d8f
TL
253 "interfaces match the",
254 "same shared network",
255 share -> interface -> name,
256 tmp -> name);
257 }
258 }
259 }
260 }
261
d2bc90bd
TL
262#if defined (LINUX_SLASHPROC_DISCOVERY)
263 /* On Linux, interfaces that don't have IP addresses don't show up
264 in the SIOCGIFCONF syscall. We got away with this prior to
265 Linux 2.1 because we would give each interface an IP address of
266 0.0.0.0 before trying to boot, but that doesn't work after 2.1
267 because we're using LPF, because we can't configure interfaces
268 with IP addresses of 0.0.0.0 anymore (grumble). This only
269 matters for the DHCP client, of course - the relay agent and
270 server should only care about interfaces that are configured
271 with IP addresses anyway.
272
273 The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
274 that, when read, prints a human readable network status. We
275 extract the names of the network devices by skipping the first
276 two lines (which are header) and then parsing off everything
277 up to the colon in each subsequent line - these lines start
278 with the interface name, then a colon, then a bunch of
279 statistics. Yes, Virgina, this is a kludge, but you work
280 with what you have. */
281
282 if (state == DISCOVER_UNCONFIGURED) {
283 FILE *proc_dev;
284 char buffer [256];
285 int skip = 2;
286
287 proc_dev = fopen (PROCDEV_DEVICE, "r");
288 if (!proc_dev)
8ae2d595 289 log_fatal ("%s: %m", PROCDEV_DEVICE);
d2bc90bd
TL
290
291 while (fgets (buffer, sizeof buffer, proc_dev)) {
292 char *name = buffer;
293 char *sep;
294
295 /* Skip the first two blocks, which are header
296 lines. */
297 if (skip) {
298 --skip;
299 continue;
300 }
301
302 sep = strrchr (buffer, ':');
303 if (sep)
304 *sep = '\0';
305 while (*name == ' ')
306 name++;
307
308 /* See if we've seen an interface that matches
309 this one. */
310 for (tmp = interfaces; tmp; tmp = tmp -> next)
311 if (!strcmp (tmp -> name, name))
312 break;
313
314 /* If we found one, nothing more to do.. */
315 if (tmp)
316 continue;
317
318 /* Otherwise, allocate one. */
319 tmp = ((struct interface_info *)
320 dmalloc (sizeof *tmp, "discover_interfaces"));
321 if (!tmp)
8ae2d595 322 log_fatal ("Insufficient memory to %s %s",
d2bc90bd
TL
323 "record interface", name);
324 memset (tmp, 0, sizeof *tmp);
325 strcpy (tmp -> name, name);
326
327 tmp -> flags = ir;
328 tmp -> next = interfaces;
329 interfaces = tmp;
330 }
331 fclose (proc_dev);
332 }
333#endif
334
335 /* Now cycle through all the interfaces we found, looking for
336 hardware addresses. */
337#if defined (SIOCGIFHWADDR) && !defined (AF_LINK)
338 for (tmp = interfaces; tmp; tmp = tmp -> next) {
339 struct ifreq ifr;
340 struct sockaddr sa;
341 int b, sk;
342
343 if (!tmp -> ifp) {
344 /* Make up an ifreq structure. */
345 tif = (struct ifreq *)malloc (sizeof (struct ifreq));
346 if (!tif)
8ae2d595 347 log_fatal ("no space to remember ifp.");
d2bc90bd
TL
348 memset (tif, 0, sizeof (struct ifreq));
349 strcpy (tif -> ifr_name, tmp -> name);
350 tmp -> ifp = tif;
351 }
352
353 /* Read the hardware address from this interface. */
354 ifr = *tmp -> ifp;
355 if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
356 continue;
357
358 sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
359
360 switch (sa.sa_family) {
361#ifdef 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 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 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 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 default:
8ae2d595 400 log_fatal ("%s: unknown hardware address type %d",
d2bc90bd
TL
401 ifr.ifr_name, sa.sa_family);
402 }
403 }
404#endif /* defined (SIOCGIFHWADDR) && !defined (AF_LINK) */
405
fa226d8f
TL
406 /* If we're just trying to get a list of interfaces that we might
407 be able to configure, we can quit now. */
408 if (state == DISCOVER_UNCONFIGURED)
409 return;
410
411 /* Weed out the interfaces that did not have IP addresses. */
412 last = (struct interface_info *)0;
413 for (tmp = interfaces; tmp; tmp = next) {
414 next = tmp -> next;
415 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
416 state == DISCOVER_REQUESTED)
417 tmp -> flags &= ~(INTERFACE_AUTOMATIC |
418 INTERFACE_REQUESTED);
419 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
420 if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
8ae2d595 421 log_fatal ("%s: not found", tmp -> name);
fa226d8f
TL
422 if (!last)
423 interfaces = interfaces -> next;
424 else
425 last -> next = tmp -> next;
426
427 /* Remember the interface in case we need to know
428 about it later. */
429 tmp -> next = dummy_interfaces;
430 dummy_interfaces = tmp;
431 continue;
432 }
433 last = tmp;
434
435 memcpy (&foo, &tmp -> ifp -> ifr_addr,
436 sizeof tmp -> ifp -> ifr_addr);
437
438 /* We must have a subnet declaration for each interface. */
439 if (!tmp -> shared_network && (state == DISCOVER_SERVER))
8ae2d595 440 log_fatal ("No subnet declaration for %s (%s).",
fa226d8f
TL
441 tmp -> name, inet_ntoa (foo.sin_addr));
442
443 /* Find subnets that don't have valid interface
444 addresses... */
445 for (subnet = (tmp -> shared_network
446 ? tmp -> shared_network -> subnets
447 : (struct subnet *)0);
448 subnet; subnet = subnet -> next_sibling) {
449 if (!subnet -> interface_address.len) {
450 /* Set the interface address for this subnet
451 to the first address we found. */
452 subnet -> interface_address.len = 4;
453 memcpy (subnet -> interface_address.iabuf,
454 &foo.sin_addr.s_addr, 4);
455 }
456 }
457
458 /* Register the interface... */
459 if_register_receive (tmp);
460 if_register_send (tmp);
461 }
462
463 /* Now register all the remaining interfaces as protocols. */
464 for (tmp = interfaces; tmp; tmp = tmp -> next)
465 add_protocol (tmp -> name, tmp -> rfdesc, got_one, tmp);
466
467 close (sock);
468
d2bc90bd
TL
469 maybe_setup_fallback ();
470}
471
472struct interface_info *setup_fallback ()
473{
474 fallback_interface =
475 ((struct interface_info *)
476 dmalloc (sizeof *fallback_interface, "discover_interfaces"));
477 if (!fallback_interface)
8ae2d595 478 log_fatal ("Insufficient memory to record fallback interface.");
d2bc90bd
TL
479 memset (fallback_interface, 0, sizeof *fallback_interface);
480 strcpy (fallback_interface -> name, "fallback");
481 fallback_interface -> shared_network =
482 new_shared_network ("parse_statement");
483 if (!fallback_interface -> shared_network)
8ae2d595 484 log_fatal ("No memory for shared subnet");
d2bc90bd
TL
485 memset (fallback_interface -> shared_network, 0,
486 sizeof (struct shared_network));
487 fallback_interface -> shared_network -> name = "fallback-net";
488 return fallback_interface;
fa226d8f
TL
489}
490
491void reinitialize_interfaces ()
492{
493 struct interface_info *ip;
494
495 for (ip = interfaces; ip; ip = ip -> next) {
496 if_reinitialize_receive (ip);
497 if_reinitialize_send (ip);
498 }
499
d2bc90bd
TL
500 if (fallback_interface)
501 if_reinitialize_send (fallback_interface);
fa226d8f
TL
502
503 interfaces_invalidated = 1;
504}
d2bc90bd
TL
505
506void got_one (l)
fa226d8f
TL
507 struct protocol *l;
508{
509 struct sockaddr_in from;
510 struct hardware hfrom;
511 struct iaddr ifrom;
512 int result;
513 union {
514 unsigned char packbuf [4095]; /* Packet input buffer.
515 Must be as large as largest
516 possible MTU. */
517 struct dhcp_packet packet;
518 } u;
519 struct interface_info *ip = l -> local;
520
521 if ((result =
522 receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
8ae2d595 523 log_error ("receive_packet failed on %s: %m", ip -> name);
fa226d8f
TL
524 return;
525 }
526 if (result == 0)
527 return;
528
529 if (bootp_packet_handler) {
530 ifrom.len = 4;
531 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
532
533 (*bootp_packet_handler) (ip, &u.packet, result,
534 from.sin_port, ifrom, &hfrom);
535 }
536}
537