]>
Commit | Line | Data |
---|---|---|
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 | |
44 | static 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 | 51 | struct interface_info *interfaces, *dummy_interfaces, *fallback_interface; |
fa226d8f TL |
52 | extern int interfaces_invalidated; |
53 | int quiet_interface_discovery; | |
54 | ||
55 | void (*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 | ||
64 | void 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 | ||
472 | struct 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 | ||
491 | void 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 | |
506 | void 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 |