]>
Commit | Line | Data |
---|---|---|
98bd7ca0 | 1 | /* discover.c |
fa226d8f | 2 | |
98bd7ca0 | 3 | Find and identify the network interfaces. */ |
fa226d8f TL |
4 | |
5 | /* | |
109fa1d0 | 6 | * Copyright (c) 2004-2020 by Internet Systems Consortium, Inc. ("ISC") |
98311e4b | 7 | * Copyright (c) 1995-2003 by Internet Software Consortium |
fa226d8f | 8 | * |
7512d88b TM |
9 | * This Source Code Form is subject to the terms of the Mozilla Public |
10 | * License, v. 2.0. If a copy of the MPL was not distributed with this | |
11 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. | |
fa226d8f | 12 | * |
98311e4b DH |
13 | * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
14 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
15 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
16 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
17 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
18 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
19 | * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
fa226d8f | 20 | * |
98311e4b DH |
21 | * Internet Systems Consortium, Inc. |
22 | * 950 Charter Street | |
23 | * Redwood City, CA 94063 | |
24 | * <info@isc.org> | |
2c85ac9b | 25 | * https://www.isc.org/ |
49733f31 | 26 | * |
fa226d8f TL |
27 | */ |
28 | ||
fa226d8f | 29 | #include "dhcpd.h" |
fe5b0fdd | 30 | |
38c4774a SR |
31 | /* length of line we can read from the IF file, 256 is too small in some cases */ |
32 | #define IF_LINE_LENGTH 1024 | |
33 | ||
fe5b0fdd | 34 | #define BSD_COMP /* needed on Solaris for SIOCGLIFNUM */ |
fa226d8f | 35 | #include <sys/ioctl.h> |
fe5b0fdd | 36 | #include <errno.h> |
fa226d8f | 37 | |
8da06bb1 DH |
38 | #ifdef HAVE_NET_IF6_H |
39 | # include <net/if6.h> | |
40 | #endif | |
41 | ||
109fa1d0 TM |
42 | struct interface_info *interfaces = 0; |
43 | struct interface_info *dummy_interfaces = 0; | |
44 | struct interface_info *fallback_interface = 0; | |
45 | ||
d758ad8c | 46 | int interfaces_invalidated; |
fa226d8f | 47 | int quiet_interface_discovery; |
6c7e6157 TM |
48 | u_int16_t local_port = 0; |
49 | u_int16_t remote_port = 0; | |
563f0b8a | 50 | u_int16_t relay_port = 0; |
785c1a51 | 51 | int dhcpv4_over_dhcpv6 = 0; |
20916cae TL |
52 | int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *); |
53 | int (*dhcp_interface_discovery_hook) (struct interface_info *); | |
cf75fef2 | 54 | isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *); |
a034015f | 55 | int (*dhcp_interface_shutdown_hook) (struct interface_info *); |
38287932 TL |
56 | |
57 | struct in_addr limited_broadcast; | |
98bd7ca0 | 58 | |
4ba58919 | 59 | int local_family = AF_INET; |
38287932 | 60 | struct in_addr local_address; |
fe5b0fdd | 61 | |
a2a0f98c FD |
62 | #ifdef DHCPv6 |
63 | /* | |
64 | * Another clear abuse of the fact that undefined IP addresses are all zeroes. | |
65 | */ | |
66 | struct in6_addr local_address6; | |
67 | int bind_local_address6 = 0; | |
68 | #endif /* DHCPv6 */ | |
69 | ||
a34feb7d TM |
70 | void (*bootp_packet_handler) (struct interface_info *, |
71 | struct dhcp_packet *, unsigned, | |
72 | unsigned int, | |
73 | struct iaddr, struct hardware *); | |
fe5b0fdd DH |
74 | |
75 | #ifdef DHCPv6 | |
98bd7ca0 DH |
76 | void (*dhcpv6_packet_handler)(struct interface_info *, |
77 | const char *, int, | |
78 | int, const struct iaddr *, | |
79 | isc_boolean_t); | |
fe5b0fdd | 80 | #endif /* DHCPv6 */ |
98bd7ca0 | 81 | |
fa226d8f | 82 | |
acc21512 | 83 | omapi_object_type_t *dhcp_type_interface; |
fc33f8c5 TL |
84 | #if defined (TRACING) |
85 | trace_type_t *interface_trace; | |
86 | trace_type_t *inpacket_trace; | |
87 | trace_type_t *outpacket_trace; | |
88 | #endif | |
89 | struct interface_info **interface_vector; | |
90 | int interface_count; | |
91 | int interface_max; | |
acc21512 | 92 | |
20916cae TL |
93 | OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface) |
94 | ||
a034015f TL |
95 | isc_result_t interface_setup () |
96 | { | |
97 | isc_result_t status; | |
98 | status = omapi_object_type_register (&dhcp_type_interface, | |
99 | "interface", | |
100 | dhcp_interface_set_value, | |
101 | dhcp_interface_get_value, | |
102 | dhcp_interface_destroy, | |
103 | dhcp_interface_signal_handler, | |
104 | dhcp_interface_stuff_values, | |
105 | dhcp_interface_lookup, | |
106 | dhcp_interface_create, | |
107 | dhcp_interface_remove, | |
108 | 0, 0, 0, | |
109 | sizeof (struct interface_info), | |
98311e4b | 110 | interface_initialize, RC_MISC); |
a034015f TL |
111 | if (status != ISC_R_SUCCESS) |
112 | log_fatal ("Can't register interface object type: %s", | |
113 | isc_result_totext (status)); | |
fc33f8c5 | 114 | |
a034015f TL |
115 | return status; |
116 | } | |
117 | ||
fc33f8c5 TL |
118 | #if defined (TRACING) |
119 | void interface_trace_setup () | |
120 | { | |
121 | interface_trace = trace_type_register ("interface", (void *)0, | |
122 | trace_interface_input, | |
123 | trace_interface_stop, MDL); | |
124 | inpacket_trace = trace_type_register ("inpacket", (void *)0, | |
125 | trace_inpacket_input, | |
126 | trace_inpacket_stop, MDL); | |
127 | outpacket_trace = trace_type_register ("outpacket", (void *)0, | |
128 | trace_outpacket_input, | |
129 | trace_outpacket_stop, MDL); | |
130 | } | |
131 | #endif | |
132 | ||
08921fe0 TL |
133 | isc_result_t interface_initialize (omapi_object_t *ipo, |
134 | const char *file, int line) | |
135 | { | |
136 | struct interface_info *ip = (struct interface_info *)ipo; | |
137 | ip -> rfdesc = ip -> wfdesc = -1; | |
138 | return ISC_R_SUCCESS; | |
139 | } | |
140 | ||
fa226d8f | 141 | |
98bd7ca0 DH |
142 | /* |
143 | * Scanning for Interfaces | |
144 | * ----------------------- | |
145 | * | |
146 | * To find interfaces, we create an iterator that abstracts out most | |
147 | * of the platform specifics. Use is fairly straightforward: | |
148 | * | |
149 | * - begin_iface_scan() starts the process. | |
150 | * - Use next_iface() until it returns 0. | |
151 | * - end_iface_scan() performs any necessary cleanup. | |
152 | * | |
153 | * We check for errors on each call to next_iface(), which returns a | |
154 | * description of the error as a string if any occurs. | |
155 | * | |
156 | * We currently have code for Solaris and Linux. Other systems need | |
157 | * to have code written. | |
158 | * | |
159 | * NOTE: the long-term goal is to use the interface code from BIND 9. | |
160 | */ | |
161 | ||
8da06bb1 DH |
162 | #if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && defined(SIOCGLIFFLAGS) |
163 | ||
164 | /* HP/UX doesn't define struct lifconf, instead they define struct | |
165 | * if_laddrconf. Similarly, 'struct lifreq' and 'struct lifaddrreq'. | |
166 | */ | |
167 | #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF | |
168 | # define lifc_len iflc_len | |
169 | # define lifc_buf iflc_buf | |
170 | # define lifc_req iflc_req | |
171 | # define LIFCONF if_laddrconf | |
172 | #else | |
173 | # define ISC_HAVE_LIFC_FAMILY 1 | |
174 | # define ISC_HAVE_LIFC_FLAGS 1 | |
175 | # define LIFCONF lifconf | |
176 | #endif | |
177 | ||
178 | #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ | |
179 | # define lifr_addr iflr_addr | |
180 | # define lifr_name iflr_name | |
181 | # define lifr_dstaddr iflr_dstaddr | |
182 | # define lifr_flags iflr_flags | |
183 | # define sockaddr_storage sockaddr_ext | |
184 | # define ss_family sa_family | |
185 | # define LIFREQ if_laddrreq | |
186 | #else | |
187 | # define LIFREQ lifreq | |
188 | #endif | |
189 | ||
190 | #ifndef IF_NAMESIZE | |
191 | # if defined(LIFNAMSIZ) | |
192 | # define IF_NAMESIZE LIFNAMSIZ | |
a57df74a | 193 | # elif defined(IFNAMSIZ) |
8da06bb1 DH |
194 | # define IF_NAMESIZE IFNAMSIZ |
195 | # else | |
196 | # define IF_NAMESIZE 16 | |
197 | # endif | |
198 | #endif | |
b8c0eda0 MA |
199 | #elif !defined(__linux) && !defined(HAVE_IFADDRS_H) |
200 | # define SIOCGLIFCONF SIOCGIFCONF | |
201 | # define SIOCGLIFFLAGS SIOCGIFFLAGS | |
202 | # define LIFREQ ifreq | |
203 | # define LIFCONF ifconf | |
204 | # define lifr_name ifr_name | |
205 | # define lifr_addr ifr_addr | |
206 | # define lifr_flags ifr_flags | |
207 | # define lifc_len ifc_len | |
208 | # define lifc_buf ifc_buf | |
209 | # define lifc_req ifc_req | |
210 | #ifdef _AIX | |
211 | # define ss_family __ss_family | |
212 | #endif | |
213 | #endif | |
8da06bb1 | 214 | |
b8c0eda0 | 215 | #if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS) |
98bd7ca0 DH |
216 | /* |
217 | * Solaris support | |
218 | * --------------- | |
219 | * | |
220 | * The SIOCGLIFCONF ioctl() are the extension that you need to use | |
221 | * on Solaris to get information about IPv6 addresses. | |
222 | * | |
223 | * Solaris' extended interface is documented in the if_tcp man page. | |
224 | */ | |
225 | ||
226 | /* | |
227 | * Structure holding state about the scan. | |
228 | */ | |
229 | struct iface_conf_list { | |
230 | int sock; /* file descriptor used to get information */ | |
231 | int num; /* total number of interfaces */ | |
8da06bb1 | 232 | struct LIFCONF conf; /* structure used to get information */ |
98bd7ca0 DH |
233 | int next; /* next interface to retrieve when iterating */ |
234 | }; | |
235 | ||
236 | /* | |
237 | * Structure used to return information about a specific interface. | |
238 | */ | |
239 | struct iface_info { | |
8da06bb1 | 240 | char name[IF_NAMESIZE+1]; /* name of the interface, e.g. "bge0" */ |
98bd7ca0 DH |
241 | struct sockaddr_storage addr; /* address information */ |
242 | isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */ | |
243 | }; | |
244 | ||
245 | /* | |
246 | * Start a scan of interfaces. | |
247 | * | |
248 | * The iface_conf_list structure maintains state for this process. | |
249 | */ | |
250 | int | |
251 | begin_iface_scan(struct iface_conf_list *ifaces) { | |
8da06bb1 | 252 | #ifdef ISC_PLATFORM_HAVELIFNUM |
98bd7ca0 | 253 | struct lifnum lifnum; |
8da06bb1 DH |
254 | #else |
255 | int lifnum; | |
256 | #endif | |
98bd7ca0 | 257 | |
97050349 | 258 | ifaces->sock = socket(local_family, SOCK_DGRAM, IPPROTO_UDP); |
98bd7ca0 DH |
259 | if (ifaces->sock < 0) { |
260 | log_error("Error creating socket to list interfaces; %m"); | |
261 | return 0; | |
262 | } | |
263 | ||
264 | memset(&lifnum, 0, sizeof(lifnum)); | |
8da06bb1 | 265 | #ifdef ISC_PLATFORM_HAVELIFNUM |
98bd7ca0 | 266 | lifnum.lifn_family = AF_UNSPEC; |
8da06bb1 | 267 | #endif |
b8c0eda0 | 268 | #ifdef SIOCGLIFNUM |
98bd7ca0 DH |
269 | if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) { |
270 | log_error("Error finding total number of interfaces; %m"); | |
271 | close(ifaces->sock); | |
272 | ifaces->sock = -1; | |
273 | return 0; | |
274 | } | |
275 | ||
8da06bb1 | 276 | #ifdef ISC_PLATFORM_HAVELIFNUM |
98bd7ca0 | 277 | ifaces->num = lifnum.lifn_count; |
8da06bb1 DH |
278 | #else |
279 | ifaces->num = lifnum; | |
280 | #endif | |
b8c0eda0 MA |
281 | #else |
282 | ifaces->num = 64; | |
283 | #endif /* SIOCGLIFNUM */ | |
8da06bb1 | 284 | |
98bd7ca0 | 285 | memset(&ifaces->conf, 0, sizeof(ifaces->conf)); |
8da06bb1 | 286 | #ifdef ISC_HAVE_LIFC_FAMILY |
98bd7ca0 | 287 | ifaces->conf.lifc_family = AF_UNSPEC; |
8da06bb1 DH |
288 | #endif |
289 | ifaces->conf.lifc_len = ifaces->num * sizeof(struct LIFREQ); | |
98bd7ca0 DH |
290 | ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL); |
291 | if (ifaces->conf.lifc_buf == NULL) { | |
292 | log_fatal("Out of memory getting interface list."); | |
293 | } | |
294 | ||
295 | if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) { | |
296 | log_error("Error getting interfaces configuration list; %m"); | |
297 | dfree(ifaces->conf.lifc_buf, MDL); | |
298 | close(ifaces->sock); | |
299 | ifaces->sock = -1; | |
300 | return 0; | |
301 | } | |
302 | ||
303 | ifaces->next = 0; | |
304 | ||
305 | return 1; | |
306 | } | |
307 | ||
308 | /* | |
309 | * Retrieve the next interface. | |
310 | * | |
311 | * Returns information in the info structure. | |
99fe695e | 312 | * Sets err to 1 if there is an error, otherwise 0. |
98bd7ca0 DH |
313 | */ |
314 | int | |
315 | next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { | |
8da06bb1 DH |
316 | struct LIFREQ *p; |
317 | struct LIFREQ tmp; | |
7cfeb916 | 318 | isc_boolean_t foundif; |
7285af30 DH |
319 | #if defined(sun) || defined(__linux) |
320 | /* Pointer used to remove interface aliases. */ | |
fa226d8f | 321 | char *s; |
7285af30 | 322 | #endif |
acc21512 | 323 | |
98bd7ca0 | 324 | do { |
7cfeb916 SR |
325 | foundif = ISC_FALSE; |
326 | ||
98bd7ca0 DH |
327 | if (ifaces->next >= ifaces->num) { |
328 | *err = 0; | |
329 | return 0; | |
330 | } | |
fa226d8f | 331 | |
98bd7ca0 DH |
332 | p = ifaces->conf.lifc_req; |
333 | p += ifaces->next; | |
c73ced69 | 334 | |
98bd7ca0 DH |
335 | if (strlen(p->lifr_name) >= sizeof(info->name)) { |
336 | *err = 1; | |
337 | log_error("Interface name '%s' too long", p->lifr_name); | |
338 | return 0; | |
339 | } | |
7cfeb916 SR |
340 | |
341 | /* Reject if interface address family does not match */ | |
342 | if (p->lifr_addr.ss_family != local_family) { | |
343 | ifaces->next++; | |
344 | continue; | |
345 | } | |
346 | ||
b7bfb2c7 TM |
347 | memset(info, 0, sizeof(struct iface_info)); |
348 | strncpy(info->name, p->lifr_name, sizeof(info->name) - 1); | |
b8c0eda0 | 349 | memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr)); |
c73ced69 | 350 | |
fe5b0fdd | 351 | #if defined(sun) || defined(__linux) |
98bd7ca0 DH |
352 | /* interface aliases look like "eth0:1" or "wlan1:3" */ |
353 | s = strchr(info->name, ':'); | |
354 | if (s != NULL) { | |
355 | *s = '\0'; | |
356 | } | |
fe5b0fdd | 357 | #endif /* defined(sun) || defined(__linux) */ |
98bd7ca0 | 358 | |
7cfeb916 SR |
359 | foundif = ISC_TRUE; |
360 | } while ((foundif == ISC_FALSE) || | |
361 | (strncmp(info->name, "dummy", 5) == 0)); | |
98bd7ca0 DH |
362 | |
363 | memset(&tmp, 0, sizeof(tmp)); | |
b7bfb2c7 | 364 | strncpy(tmp.lifr_name, info->name, sizeof(tmp.lifr_name) - 1); |
98bd7ca0 DH |
365 | if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) { |
366 | log_error("Error getting interface flags for '%s'; %m", | |
367 | p->lifr_name); | |
368 | *err = 1; | |
369 | return 0; | |
370 | } | |
371 | info->flags = tmp.lifr_flags; | |
372 | ||
373 | ifaces->next++; | |
374 | *err = 0; | |
375 | return 1; | |
376 | } | |
377 | ||
378 | /* | |
379 | * End scan of interfaces. | |
380 | */ | |
381 | void | |
382 | end_iface_scan(struct iface_conf_list *ifaces) { | |
383 | dfree(ifaces->conf.lifc_buf, MDL); | |
384 | close(ifaces->sock); | |
385 | ifaces->sock = -1; | |
386 | } | |
387 | ||
b8c0eda0 | 388 | #else |
99fe695e SK |
389 | |
390 | /* | |
e191f1e8 | 391 | * BSD/Linux support |
99fe695e SK |
392 | * ----------- |
393 | * | |
e191f1e8 | 394 | * FreeBSD, NetBSD, OpenBSD, OS X/macOS and Linux all have the getifaddrs() |
99fe695e SK |
395 | * function. |
396 | * | |
397 | * The getifaddrs() man page describes the use. | |
398 | */ | |
399 | ||
400 | #include <ifaddrs.h> | |
401 | ||
402 | /* | |
403 | * Structure holding state about the scan. | |
404 | */ | |
405 | struct iface_conf_list { | |
406 | struct ifaddrs *head; /* beginning of the list */ | |
407 | struct ifaddrs *next; /* current position in the list */ | |
408 | }; | |
409 | ||
410 | /* | |
411 | * Structure used to return information about a specific interface. | |
412 | */ | |
413 | struct iface_info { | |
414 | char name[IFNAMSIZ]; /* name of the interface, e.g. "bge0" */ | |
415 | struct sockaddr_storage addr; /* address information */ | |
416 | isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */ | |
417 | }; | |
418 | ||
419 | /* | |
420 | * Start a scan of interfaces. | |
421 | * | |
422 | * The iface_conf_list structure maintains state for this process. | |
423 | */ | |
424 | int | |
425 | begin_iface_scan(struct iface_conf_list *ifaces) { | |
426 | if (getifaddrs(&ifaces->head) != 0) { | |
427 | log_error("Error getting interfaces; %m"); | |
428 | return 0; | |
429 | } | |
430 | ifaces->next = ifaces->head; | |
431 | return 1; | |
432 | } | |
433 | ||
434 | /* | |
435 | * Retrieve the next interface. | |
436 | * | |
437 | * Returns information in the info structure. | |
438 | * Sets err to 1 if there is an error, otherwise 0. | |
439 | */ | |
440 | int | |
441 | next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { | |
e191f1e8 FD |
442 | size_t sa_len = 0; |
443 | ||
99fe695e SK |
444 | if (ifaces->next == NULL) { |
445 | *err = 0; | |
446 | return 0; | |
447 | } | |
448 | if (strlen(ifaces->next->ifa_name) >= sizeof(info->name)) { | |
449 | log_error("Interface name '%s' too long", | |
450 | ifaces->next->ifa_name); | |
451 | *err = 1; | |
452 | return 0; | |
453 | } | |
b7bfb2c7 TM |
454 | memset(info, 0, sizeof(struct iface_info)); |
455 | strncpy(info->name, ifaces->next->ifa_name, sizeof(info->name) - 1); | |
e191f1e8 FD |
456 | memset(&info->addr, 0 , sizeof(info->addr)); |
457 | /* | |
458 | * getifaddrs() can on Linux with some interfaces like PPP or TEQL | |
459 | * result in a record with no address (ifa_addr). | |
460 | */ | |
461 | if (ifaces->next->ifa_addr != NULL) { | |
462 | /* Linux lacks the sa_len member in struct sockaddr. */ | |
463 | #if defined(__linux) | |
464 | if (ifaces->next->ifa_addr->sa_family == AF_INET) | |
465 | sa_len = sizeof(struct sockaddr_in); | |
466 | else if (ifaces->next->ifa_addr->sa_family == AF_INET6) | |
467 | sa_len = sizeof(struct sockaddr_in6); | |
468 | #else | |
469 | sa_len = ifaces->next->ifa_addr->sa_len; | |
470 | #endif | |
471 | memcpy(&info->addr, ifaces->next->ifa_addr, sa_len); | |
472 | } | |
99fe695e SK |
473 | info->flags = ifaces->next->ifa_flags; |
474 | ifaces->next = ifaces->next->ifa_next; | |
475 | *err = 0; | |
476 | return 1; | |
477 | } | |
478 | ||
479 | /* | |
480 | * End scan of interfaces. | |
481 | */ | |
482 | void | |
483 | end_iface_scan(struct iface_conf_list *ifaces) { | |
484 | freeifaddrs(ifaces->head); | |
485 | ifaces->head = NULL; | |
486 | ifaces->next = NULL; | |
487 | } | |
98bd7ca0 DH |
488 | #endif |
489 | ||
490 | /* XXX: perhaps create drealloc() rather than do it manually */ | |
491 | void | |
492 | add_ipv4_addr_to_interface(struct interface_info *iface, | |
493 | const struct in_addr *addr) { | |
494 | /* | |
495 | * We don't expect a lot of addresses per IPv4 interface, so | |
496 | * we use 4, as our "chunk size" for collecting addresses. | |
497 | */ | |
498 | if (iface->addresses == NULL) { | |
499 | iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL); | |
500 | if (iface->addresses == NULL) { | |
501 | log_fatal("Out of memory saving IPv4 address " | |
502 | "on interface."); | |
503 | } | |
504 | iface->address_count = 0; | |
505 | iface->address_max = 4; | |
506 | } else if (iface->address_count >= iface->address_max) { | |
507 | struct in_addr *tmp; | |
508 | int new_max; | |
509 | ||
510 | new_max = iface->address_max + 4; | |
511 | tmp = dmalloc(new_max * sizeof(struct in_addr), MDL); | |
512 | if (tmp == NULL) { | |
513 | log_fatal("Out of memory saving IPv4 address " | |
514 | "on interface."); | |
515 | } | |
516 | memcpy(tmp, | |
517 | iface->addresses, | |
518 | iface->address_max * sizeof(struct in_addr)); | |
519 | dfree(iface->addresses, MDL); | |
520 | iface->addresses = tmp; | |
521 | iface->address_max = new_max; | |
522 | } | |
523 | iface->addresses[iface->address_count++] = *addr; | |
524 | } | |
525 | ||
fe5b0fdd | 526 | #ifdef DHCPv6 |
98bd7ca0 DH |
527 | /* XXX: perhaps create drealloc() rather than do it manually */ |
528 | void | |
529 | add_ipv6_addr_to_interface(struct interface_info *iface, | |
530 | const struct in6_addr *addr) { | |
531 | /* | |
532 | * Each IPv6 interface will have at least two IPv6 addresses, | |
533 | * and likely quite a few more. So we use 8, as our "chunk size" for | |
534 | * collecting addresses. | |
535 | */ | |
536 | if (iface->v6addresses == NULL) { | |
537 | iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL); | |
538 | if (iface->v6addresses == NULL) { | |
539 | log_fatal("Out of memory saving IPv6 address " | |
540 | "on interface."); | |
541 | } | |
542 | iface->v6address_count = 0; | |
543 | iface->v6address_max = 8; | |
544 | } else if (iface->v6address_count >= iface->v6address_max) { | |
545 | struct in6_addr *tmp; | |
546 | int new_max; | |
547 | ||
548 | new_max = iface->v6address_max + 8; | |
549 | tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL); | |
550 | if (tmp == NULL) { | |
551 | log_fatal("Out of memory saving IPv6 address " | |
552 | "on interface."); | |
553 | } | |
554 | memcpy(tmp, | |
555 | iface->v6addresses, | |
556 | iface->v6address_max * sizeof(struct in6_addr)); | |
557 | dfree(iface->v6addresses, MDL); | |
558 | iface->v6addresses = tmp; | |
559 | iface->v6address_max = new_max; | |
560 | } | |
561 | iface->v6addresses[iface->v6address_count++] = *addr; | |
562 | } | |
fe5b0fdd | 563 | #endif /* DHCPv6 */ |
98bd7ca0 DH |
564 | |
565 | /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces. | |
566 | For each interface that's of type INET and not the loopback interface, | |
567 | register that interface with the network I/O software, figure out what | |
568 | subnet it's on, and add it to the list of interfaces. */ | |
569 | ||
570 | void | |
571 | discover_interfaces(int state) { | |
572 | struct iface_conf_list ifaces; | |
573 | struct iface_info info; | |
574 | int err; | |
575 | ||
28868515 | 576 | struct interface_info *tmp; |
98bd7ca0 DH |
577 | struct interface_info *last, *next; |
578 | ||
28868515 SK |
579 | #ifdef DHCPv6 |
580 | char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; | |
581 | #endif /* DHCPv6 */ | |
582 | ||
98bd7ca0 DH |
583 | |
584 | struct subnet *subnet; | |
585 | int ir; | |
586 | isc_result_t status; | |
587 | int wifcount = 0; | |
563f0b8a FD |
588 | #ifdef RELAY_PORT |
589 | int updone = 0; | |
590 | int downdone = 0; | |
591 | #endif | |
98bd7ca0 DH |
592 | |
593 | static int setup_fallback = 0; | |
594 | ||
595 | if (!begin_iface_scan(&ifaces)) { | |
596 | log_fatal("Can't get list of interfaces."); | |
d902d52e | 597 | } |
615a574a | 598 | |
fa226d8f TL |
599 | /* If we already have a list of interfaces, and we're running as |
600 | a DHCP server, the interfaces were requested. */ | |
601 | if (interfaces && (state == DISCOVER_SERVER || | |
602 | state == DISCOVER_RELAY || | |
603 | state == DISCOVER_REQUESTED)) | |
604 | ir = 0; | |
605 | else if (state == DISCOVER_UNCONFIGURED) | |
606 | ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC; | |
f2e70402 | 607 | else { |
fa226d8f | 608 | ir = INTERFACE_REQUESTED; |
f2e70402 TM |
609 | if (state == DISCOVER_RELAY && local_family == AF_INET) { |
610 | /* We're a v4 relay without specifically requested | |
611 | * interfaces, so mark them all as bidirectional. */ | |
612 | ir |= INTERFACE_STREAMS; | |
613 | } | |
614 | } | |
fa226d8f | 615 | |
d2bc90bd | 616 | /* Cycle through the list of interfaces looking for IP addresses. */ |
98bd7ca0 | 617 | while (next_iface(&info, &err, &ifaces)) { |
fa226d8f | 618 | |
5c0ba9a1 | 619 | /* See if we've seen an interface that matches this one. */ |
98bd7ca0 DH |
620 | for (tmp = interfaces; tmp; tmp = tmp->next) { |
621 | if (!strcmp(tmp->name, info.name)) | |
5c0ba9a1 | 622 | break; |
98bd7ca0 | 623 | } |
5c0ba9a1 | 624 | |
98311e4b DH |
625 | /* Skip non broadcast interfaces (plus loopback and |
626 | point-to-point in case an OS incorrectly marks them | |
627 | as broadcast). Also skip down interfaces unless we're | |
628 | trying to get a list of configurable interfaces. */ | |
7cfeb916 SR |
629 | if ((((local_family == AF_INET && |
630 | !(info.flags & IFF_BROADCAST)) || | |
631 | #ifdef DHCPv6 | |
632 | (local_family == AF_INET6 && | |
633 | !(info.flags & IFF_MULTICAST)) || | |
634 | #endif | |
98bd7ca0 DH |
635 | info.flags & IFF_LOOPBACK || |
636 | info.flags & IFF_POINTOPOINT) && !tmp) || | |
637 | (!(info.flags & IFF_UP) && | |
fa226d8f TL |
638 | state != DISCOVER_UNCONFIGURED)) |
639 | continue; | |
640 | ||
fa226d8f TL |
641 | /* If there isn't already an interface by this name, |
642 | allocate one. */ | |
98bd7ca0 DH |
643 | if (tmp == NULL) { |
644 | status = interface_allocate(&tmp, MDL); | |
645 | if (status != ISC_R_SUCCESS) { | |
646 | log_fatal("Error allocating interface %s: %s", | |
647 | info.name, isc_result_totext(status)); | |
648 | } | |
e119ecf6 TM |
649 | |
650 | memcpy(tmp->name, info.name, sizeof(tmp->name)); | |
651 | ||
98bd7ca0 DH |
652 | interface_snorf(tmp, ir); |
653 | interface_dereference(&tmp, MDL); | |
fc33f8c5 | 654 | tmp = interfaces; /* XXX */ |
347de8bd TL |
655 | } |
656 | ||
98bd7ca0 DH |
657 | if (dhcp_interface_discovery_hook) { |
658 | (*dhcp_interface_discovery_hook)(tmp); | |
659 | } | |
20916cae | 660 | |
98bd7ca0 DH |
661 | if ((info.addr.ss_family == AF_INET) && |
662 | (local_family == AF_INET)) { | |
663 | struct sockaddr_in *a = (struct sockaddr_in*)&info.addr; | |
fa226d8f TL |
664 | struct iaddr addr; |
665 | ||
98bd7ca0 DH |
666 | /* We don't want the loopback interface. */ |
667 | if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) && | |
668 | ((tmp->flags & INTERFACE_AUTOMATIC) && | |
785c1a51 FD |
669 | ((state == DISCOVER_SERVER) || |
670 | (state == DISCOVER_SERVER46)))) | |
98bd7ca0 DH |
671 | continue; |
672 | ||
673 | /* If the only address we have is 0.0.0.0, we | |
674 | shouldn't consider the interface configured. */ | |
675 | if (a->sin_addr.s_addr != htonl(INADDR_ANY)) | |
676 | tmp->configured = 1; | |
677 | ||
678 | add_ipv4_addr_to_interface(tmp, &a->sin_addr); | |
679 | ||
98bd7ca0 DH |
680 | /* invoke the setup hook */ |
681 | addr.len = 4; | |
682 | memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len); | |
683 | if (dhcp_interface_setup_hook) { | |
684 | (*dhcp_interface_setup_hook)(tmp, &addr); | |
685 | } | |
686 | } | |
fe5b0fdd | 687 | #ifdef DHCPv6 |
98bd7ca0 DH |
688 | else if ((info.addr.ss_family == AF_INET6) && |
689 | (local_family == AF_INET6)) { | |
690 | struct sockaddr_in6 *a = | |
691 | (struct sockaddr_in6*)&info.addr; | |
692 | struct iaddr addr; | |
fa226d8f TL |
693 | |
694 | /* We don't want the loopback interface. */ | |
98bd7ca0 DH |
695 | if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) && |
696 | ((tmp->flags & INTERFACE_AUTOMATIC) && | |
785c1a51 FD |
697 | ((state == DISCOVER_SERVER) || |
698 | (state == DISCOVER_SERVER46)))) | |
78c553c4 | 699 | continue; |
fa226d8f | 700 | |
98bd7ca0 DH |
701 | /* If the only address we have is 0.0.0.0, we |
702 | shouldn't consider the interface configured. */ | |
703 | if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)) | |
704 | tmp->configured = 1; | |
fa226d8f | 705 | |
98bd7ca0 DH |
706 | add_ipv6_addr_to_interface(tmp, &a->sin6_addr); |
707 | ||
98bd7ca0 DH |
708 | /* invoke the setup hook */ |
709 | addr.len = 16; | |
710 | memcpy(addr.iabuf, &a->sin6_addr, addr.len); | |
711 | if (dhcp_interface_setup_hook) { | |
712 | (*dhcp_interface_setup_hook)(tmp, &addr); | |
713 | } | |
fa226d8f | 714 | } |
fe5b0fdd | 715 | #endif /* DHCPv6 */ |
fa226d8f TL |
716 | } |
717 | ||
98bd7ca0 DH |
718 | if (err) { |
719 | log_fatal("Error getting interface information."); | |
720 | } | |
721 | ||
722 | end_iface_scan(&ifaces); | |
d902d52e | 723 | |
d2bc90bd | 724 | |
4ba58919 DH |
725 | /* Mock-up an 'ifp' structure which is no longer used in the |
726 | * new interface-sensing code, but is used in higher layers | |
727 | * (for example to sense fallback interfaces). | |
728 | */ | |
729 | for (tmp = interfaces ; tmp != NULL ; tmp = tmp->next) { | |
730 | if (tmp->ifp == NULL) { | |
731 | struct ifreq *tif; | |
732 | ||
733 | tif = (struct ifreq *)dmalloc(sizeof(struct ifreq), | |
734 | MDL); | |
735 | if (tif == NULL) | |
736 | log_fatal("no space for ifp mockup."); | |
737 | strcpy(tif->ifr_name, tmp->name); | |
738 | tmp->ifp = tif; | |
739 | } | |
740 | } | |
741 | ||
742 | ||
fa226d8f TL |
743 | /* If we're just trying to get a list of interfaces that we might |
744 | be able to configure, we can quit now. */ | |
bdcaf7b9 | 745 | if (state == DISCOVER_UNCONFIGURED) { |
fa226d8f | 746 | return; |
bdcaf7b9 | 747 | } |
fa226d8f TL |
748 | |
749 | /* Weed out the interfaces that did not have IP addresses. */ | |
98bd7ca0 | 750 | tmp = last = next = NULL; |
20916cae TL |
751 | if (interfaces) |
752 | interface_reference (&tmp, interfaces, MDL); | |
753 | while (tmp) { | |
754 | if (next) | |
755 | interface_dereference (&next, MDL); | |
756 | if (tmp -> next) | |
757 | interface_reference (&next, tmp -> next, MDL); | |
347de8bd | 758 | /* skip interfaces that are running already */ |
98311e4b DH |
759 | if (tmp -> flags & INTERFACE_RUNNING) { |
760 | interface_dereference(&tmp, MDL); | |
761 | if(next) | |
762 | interface_reference(&tmp, next, MDL); | |
347de8bd | 763 | continue; |
98311e4b | 764 | } |
fa226d8f TL |
765 | if ((tmp -> flags & INTERFACE_AUTOMATIC) && |
766 | state == DISCOVER_REQUESTED) | |
767 | tmp -> flags &= ~(INTERFACE_AUTOMATIC | | |
768 | INTERFACE_REQUESTED); | |
fe5b0fdd DH |
769 | |
770 | #ifdef DHCPv6 | |
98bd7ca0 | 771 | if (!(tmp->flags & INTERFACE_REQUESTED)) { |
fe5b0fdd DH |
772 | #else |
773 | if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) { | |
774 | #endif /* DHCPv6 */ | |
fa226d8f | 775 | if ((tmp -> flags & INTERFACE_REQUESTED) != ir) |
8ae2d595 | 776 | log_fatal ("%s: not found", tmp -> name); |
20916cae TL |
777 | if (!last) { |
778 | if (interfaces) | |
779 | interface_dereference (&interfaces, | |
780 | MDL); | |
fc33f8c5 | 781 | if (next) |
20916cae TL |
782 | interface_reference (&interfaces, next, MDL); |
783 | } else { | |
784 | interface_dereference (&last -> next, MDL); | |
fc33f8c5 TL |
785 | if (next) |
786 | interface_reference (&last -> next, | |
787 | next, MDL); | |
20916cae TL |
788 | } |
789 | if (tmp -> next) | |
790 | interface_dereference (&tmp -> next, MDL); | |
fa226d8f TL |
791 | |
792 | /* Remember the interface in case we need to know | |
793 | about it later. */ | |
20916cae TL |
794 | if (dummy_interfaces) { |
795 | interface_reference (&tmp -> next, | |
796 | dummy_interfaces, MDL); | |
797 | interface_dereference (&dummy_interfaces, MDL); | |
798 | } | |
799 | interface_reference (&dummy_interfaces, tmp, MDL); | |
800 | interface_dereference (&tmp, MDL); | |
801 | if (next) | |
802 | interface_reference (&tmp, next, MDL); | |
fa226d8f TL |
803 | continue; |
804 | } | |
805 | last = tmp; | |
806 | ||
fa226d8f | 807 | /* We must have a subnet declaration for each interface. */ |
98bd7ca0 DH |
808 | if (!tmp->shared_network && (state == DISCOVER_SERVER)) { |
809 | log_error("%s", ""); | |
810 | if (local_family == AF_INET) { | |
811 | log_error("No subnet declaration for %s (%s).", | |
812 | tmp->name, | |
f796f70a DH |
813 | (tmp->addresses == NULL) ? |
814 | "no IPv4 addresses" : | |
815 | inet_ntoa(tmp->addresses[0])); | |
fe5b0fdd | 816 | #ifdef DHCPv6 |
98bd7ca0 DH |
817 | } else { |
818 | if (tmp->v6addresses != NULL) { | |
819 | inet_ntop(AF_INET6, | |
820 | &tmp->v6addresses[0], | |
821 | abuf, | |
822 | sizeof(abuf)); | |
823 | } else { | |
f796f70a | 824 | strcpy(abuf, "no IPv6 addresses"); |
98bd7ca0 | 825 | } |
00a002fc | 826 | log_error("No subnet6 declaration for %s (%s).", |
98bd7ca0 DH |
827 | tmp->name, |
828 | abuf); | |
fe5b0fdd | 829 | #endif /* DHCPv6 */ |
98bd7ca0 DH |
830 | } |
831 | if (supports_multiple_interfaces(tmp)) { | |
21fd88ea TL |
832 | log_error ("** Ignoring requests on %s. %s", |
833 | tmp -> name, "If this is not what"); | |
834 | log_error (" you want, please write %s", | |
00a002fc MA |
835 | #ifdef DHCPv6 |
836 | (local_family != AF_INET) ? | |
837 | "a subnet6 declaration" : | |
838 | #endif | |
21fd88ea TL |
839 | "a subnet declaration"); |
840 | log_error (" in your dhcpd.conf file %s", | |
841 | "for the network segment"); | |
842 | log_error (" to %s %s %s", | |
5cefe5e5 | 843 | "which interface", |
21fd88ea TL |
844 | tmp -> name, "is attached. **"); |
845 | log_error ("%s", ""); | |
5cefe5e5 TL |
846 | goto next; |
847 | } else { | |
00a002fc MA |
848 | log_error ("You must write a %s", |
849 | #ifdef DHCPv6 | |
850 | (local_family != AF_INET) ? | |
851 | "subnet6 declaration for this" : | |
852 | #endif | |
853 | "subnet declaration for this"); | |
5cefe5e5 TL |
854 | log_error ("subnet. You cannot prevent %s", |
855 | "the DHCP server"); | |
856 | log_error ("from listening on this subnet %s", | |
857 | "because your"); | |
858 | log_fatal ("operating system does not %s.", | |
859 | "support this capability"); | |
860 | } | |
74f45f96 | 861 | } |
fa226d8f TL |
862 | |
863 | /* Find subnets that don't have valid interface | |
864 | addresses... */ | |
865 | for (subnet = (tmp -> shared_network | |
866 | ? tmp -> shared_network -> subnets | |
867 | : (struct subnet *)0); | |
868 | subnet; subnet = subnet -> next_sibling) { | |
97050349 SK |
869 | /* Set the interface address for this subnet |
870 | to the first address we found. */ | |
871 | if (subnet->interface_address.len == 0) { | |
872 | if (tmp->address_count > 0) { | |
873 | subnet->interface_address.len = 4; | |
874 | memcpy(subnet->interface_address.iabuf, | |
875 | &tmp->addresses[0].s_addr, 4); | |
876 | } else if (tmp->v6address_count > 0) { | |
877 | subnet->interface_address.len = 16; | |
878 | memcpy(subnet->interface_address.iabuf, | |
879 | &tmp->v6addresses[0].s6_addr, | |
880 | 16); | |
881 | } else { | |
882 | /* XXX: should be one */ | |
883 | log_error("%s missing an interface " | |
884 | "address", tmp->name); | |
885 | continue; | |
886 | } | |
fa226d8f TL |
887 | } |
888 | } | |
889 | ||
fc33f8c5 TL |
890 | /* Flag the index as not having been set, so that the |
891 | interface registerer can set it or not as it chooses. */ | |
892 | tmp -> index = -1; | |
893 | ||
fa226d8f | 894 | /* Register the interface... */ |
785c1a51 FD |
895 | switch (local_family) { |
896 | case AF_INET: | |
897 | if (!dhcpv4_over_dhcpv6) { | |
898 | if_register_receive(tmp); | |
899 | if_register_send(tmp); | |
900 | } else { | |
901 | /* get_hw_addr() was called by register. */ | |
902 | get_hw_addr(tmp->name, &tmp->hw_address); | |
903 | } | |
904 | break; | |
fe5b0fdd | 905 | #ifdef DHCPv6 |
785c1a51 | 906 | case AF_INET6: |
7de20a95 EH |
907 | if ((state == DISCOVER_SERVER) || |
908 | (state == DISCOVER_RELAY)) { | |
98bd7ca0 | 909 | if_register6(tmp, 1); |
785c1a51 FD |
910 | } else if (state == DISCOVER_SERVER46) { |
911 | /* get_hw_addr() was called by if_register*6 | |
912 | so now we have to call it explicitly | |
913 | to not leave the hardware address unknown | |
914 | (some code expects it cannot be. */ | |
915 | get_hw_addr(tmp->name, &tmp->hw_address); | |
98bd7ca0 | 916 | } else { |
4b8251a0 | 917 | if_register_linklocal6(tmp); |
98bd7ca0 | 918 | } |
785c1a51 | 919 | break; |
fe5b0fdd | 920 | #endif /* DHCPv6 */ |
98bd7ca0 | 921 | } |
fc33f8c5 TL |
922 | |
923 | interface_stash (tmp); | |
d902d52e | 924 | wifcount++; |
fe5b0fdd | 925 | #if defined (F_SETFD) |
785c1a51 FD |
926 | /* if_register*() are no longer always called so |
927 | descriptors must be checked. */ | |
928 | if ((tmp -> rfdesc >= 0) && | |
929 | (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0)) | |
930 | log_error ("Can't set close-on-exec on %s: %m", | |
931 | tmp -> name); | |
932 | if ((tmp -> wfdesc != tmp -> rfdesc) && | |
933 | (tmp -> wfdesc >= 0) && | |
934 | (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0)) | |
d4417aa1 TL |
935 | log_error ("Can't set close-on-exec on %s: %m", |
936 | tmp -> name); | |
d4417aa1 | 937 | #endif |
5cefe5e5 | 938 | next: |
20916cae TL |
939 | interface_dereference (&tmp, MDL); |
940 | if (next) | |
941 | interface_reference (&tmp, next, MDL); | |
fa226d8f TL |
942 | } |
943 | ||
98bf1607 SR |
944 | /* |
945 | * Now register all the remaining interfaces as protocols. | |
946 | * We register with omapi to allow for control of the interface, | |
947 | * we've already registered the fd or socket with the socket | |
948 | * manager as part of if_register_receive(). | |
949 | */ | |
acc21512 | 950 | for (tmp = interfaces; tmp; tmp = tmp -> next) { |
347de8bd TL |
951 | /* not if it's been registered before */ |
952 | if (tmp -> flags & INTERFACE_RUNNING) | |
953 | continue; | |
08921fe0 TL |
954 | if (tmp -> rfdesc == -1) |
955 | continue; | |
98bf1607 | 956 | switch (local_family) { |
06eb8bab | 957 | #ifdef DHCPv6 |
98bf1607 | 958 | case AF_INET6: |
563f0b8a FD |
959 | #ifdef RELAY_PORT |
960 | #define UPSTREAM(ifp) \ | |
961 | ((ifp->flags & INTERFACE_STREAMS) == INTERFACE_UPSTREAM) | |
962 | #define DOWNSTREAM(ifp) \ | |
963 | ((ifp->flags & INTERFACE_STREAMS) == INTERFACE_DOWNSTREAM) | |
964 | ||
965 | if (relay_port) { | |
966 | /* | |
967 | * The normal IPv6 relay only needs one | |
968 | * socket as long as we find an interface. | |
969 | * When user relay port is defined, and we | |
970 | * have two different UDP ports. One to | |
971 | * receive from DHCP client with port 547, | |
972 | * and the other is user defined for sending | |
973 | * to the server or upstream relay agent. | |
974 | * Thus we need to register sockets for one | |
975 | * upstream and one downstream interfaces. | |
976 | */ | |
977 | if (updone && UPSTREAM(tmp)) | |
978 | continue; | |
979 | if (downdone && DOWNSTREAM(tmp)) | |
980 | continue; | |
981 | } | |
982 | #endif | |
98bd7ca0 DH |
983 | status = omapi_register_io_object((omapi_object_t *)tmp, |
984 | if_readsocket, | |
06eb8bab | 985 | 0, got_one_v6, 0, 0); |
563f0b8a FD |
986 | #ifdef RELAY_PORT |
987 | if (UPSTREAM(tmp)) | |
988 | updone++; | |
989 | else | |
990 | downdone++; | |
991 | #endif | |
98bf1607 | 992 | break; |
06eb8bab | 993 | #endif /* DHCPv6 */ |
98bf1607 SR |
994 | case AF_INET: |
995 | default: | |
98bd7ca0 DH |
996 | status = omapi_register_io_object((omapi_object_t *)tmp, |
997 | if_readsocket, | |
06eb8bab | 998 | 0, got_one, 0, 0); |
98bf1607 | 999 | break; |
98bd7ca0 | 1000 | } |
98bf1607 | 1001 | |
acc21512 TL |
1002 | if (status != ISC_R_SUCCESS) |
1003 | log_fatal ("Can't register I/O handle for %s: %s", | |
1004 | tmp -> name, isc_result_totext (status)); | |
ecddae64 DH |
1005 | |
1006 | #if defined(DHCPv6) | |
4b8251a0 SR |
1007 | /* Only register the first interface for V6, since |
1008 | * servers and relays all use the same socket. | |
1009 | * XXX: This has some messy side effects if we start | |
1010 | * dynamically adding and removing interfaces, but | |
1011 | * we're well beyond that point in terms of mess. | |
ecddae64 | 1012 | */ |
563f0b8a FD |
1013 | if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY)) |
1014 | && (local_family == AF_INET6) | |
1015 | #if defined(RELAY_PORT) | |
1016 | && ((relay_port == 0) || (updone && downdone)) | |
1017 | #endif | |
1018 | ) | |
ecddae64 DH |
1019 | break; |
1020 | #endif | |
98bf1607 | 1021 | } /* for (tmp = interfaces; ... */ |
fa226d8f | 1022 | |
d902d52e TL |
1023 | if (state == DISCOVER_SERVER && wifcount == 0) { |
1024 | log_info ("%s", ""); | |
1025 | log_fatal ("Not configured to listen on any interfaces!"); | |
1026 | } | |
1027 | ||
785c1a51 FD |
1028 | if ((local_family == AF_INET) && |
1029 | !setup_fallback && !dhcpv4_over_dhcpv6) { | |
bdcaf7b9 | 1030 | setup_fallback = 1; |
98bd7ca0 | 1031 | maybe_setup_fallback(); |
bdcaf7b9 TL |
1032 | } |
1033 | ||
fe5b0fdd | 1034 | #if defined (F_SETFD) |
d4417aa1 TL |
1035 | if (fallback_interface) { |
1036 | if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0) | |
1037 | log_error ("Can't set close-on-exec on fallback: %m"); | |
1038 | if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) { | |
1039 | if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0) | |
1040 | log_error ("Can't set close-on-exec on fallback: %m"); | |
1041 | } | |
1042 | } | |
fe5b0fdd | 1043 | #endif /* F_SETFD */ |
d2bc90bd TL |
1044 | } |
1045 | ||
acc21512 TL |
1046 | int if_readsocket (h) |
1047 | omapi_object_t *h; | |
1048 | { | |
1049 | struct interface_info *ip; | |
1050 | ||
1051 | if (h -> type != dhcp_type_interface) | |
0a759381 | 1052 | return -1; |
acc21512 TL |
1053 | ip = (struct interface_info *)h; |
1054 | return ip -> rfdesc; | |
1055 | } | |
1056 | ||
20916cae | 1057 | int setup_fallback (struct interface_info **fp, const char *file, int line) |
d2bc90bd | 1058 | { |
20916cae TL |
1059 | isc_result_t status; |
1060 | ||
1061 | status = interface_allocate (&fallback_interface, file, line); | |
1062 | if (status != ISC_R_SUCCESS) | |
1063 | log_fatal ("Error allocating fallback interface: %s", | |
1064 | isc_result_totext (status)); | |
d2bc90bd | 1065 | strcpy (fallback_interface -> name, "fallback"); |
20916cae TL |
1066 | if (dhcp_interface_setup_hook) |
1067 | (*dhcp_interface_setup_hook) (fallback_interface, | |
1068 | (struct iaddr *)0); | |
1069 | status = interface_reference (fp, fallback_interface, file, line); | |
fc33f8c5 | 1070 | |
fbd9c67b | 1071 | fallback_interface -> index = -1; |
fc33f8c5 | 1072 | interface_stash (fallback_interface); |
20916cae | 1073 | return status == ISC_R_SUCCESS; |
fa226d8f TL |
1074 | } |
1075 | ||
1076 | void reinitialize_interfaces () | |
1077 | { | |
1078 | struct interface_info *ip; | |
1079 | ||
1080 | for (ip = interfaces; ip; ip = ip -> next) { | |
1081 | if_reinitialize_receive (ip); | |
1082 | if_reinitialize_send (ip); | |
1083 | } | |
1084 | ||
d2bc90bd TL |
1085 | if (fallback_interface) |
1086 | if_reinitialize_send (fallback_interface); | |
fa226d8f TL |
1087 | |
1088 | interfaces_invalidated = 1; | |
1089 | } | |
d2bc90bd | 1090 | |
acc21512 TL |
1091 | isc_result_t got_one (h) |
1092 | omapi_object_t *h; | |
fa226d8f TL |
1093 | { |
1094 | struct sockaddr_in from; | |
1095 | struct hardware hfrom; | |
1096 | struct iaddr ifrom; | |
1097 | int result; | |
1098 | union { | |
1099 | unsigned char packbuf [4095]; /* Packet input buffer. | |
1100 | Must be as large as largest | |
1101 | possible MTU. */ | |
1102 | struct dhcp_packet packet; | |
1103 | } u; | |
acc21512 TL |
1104 | struct interface_info *ip; |
1105 | ||
1106 | if (h -> type != dhcp_type_interface) | |
98bf1607 | 1107 | return DHCP_R_INVALIDARG; |
acc21512 | 1108 | ip = (struct interface_info *)h; |
fa226d8f | 1109 | |
a034015f | 1110 | again: |
fa226d8f TL |
1111 | if ((result = |
1112 | receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) { | |
8ae2d595 | 1113 | log_error ("receive_packet failed on %s: %m", ip -> name); |
acc21512 | 1114 | return ISC_R_UNEXPECTED; |
fa226d8f TL |
1115 | } |
1116 | if (result == 0) | |
acc21512 | 1117 | return ISC_R_UNEXPECTED; |
fa226d8f | 1118 | |
8bd96ccb SR |
1119 | /* |
1120 | * If we didn't at least get the fixed portion of the BOOTP | |
1121 | * packet, drop the packet. | |
1122 | * Previously we allowed packets with no sname or filename | |
1123 | * as we were aware of at least one client that did. But | |
1124 | * a bug caused short packets to not work and nobody has | |
1125 | * complained, it seems rational to tighten up that | |
1126 | * restriction. | |
1127 | */ | |
1128 | if (result < DHCP_FIXED_NON_UDP) | |
bb404b74 TL |
1129 | return ISC_R_UNEXPECTED; |
1130 | ||
7cfeb916 SR |
1131 | #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO) |
1132 | { | |
1133 | /* We retrieve the ifindex from the unused hfrom variable */ | |
1134 | unsigned int ifindex; | |
1135 | ||
1136 | memcpy(&ifindex, hfrom.hbuf, sizeof (ifindex)); | |
1137 | ||
1138 | /* | |
1139 | * Seek forward from the first interface to find the matching | |
1140 | * source interface by interface index. | |
1141 | */ | |
1142 | ip = interfaces; | |
1143 | while ((ip != NULL) && (if_nametoindex(ip->name) != ifindex)) | |
1144 | ip = ip->next; | |
1145 | if (ip == NULL) | |
1146 | return ISC_R_NOTFOUND; | |
1147 | } | |
1148 | #endif | |
1149 | ||
fa226d8f TL |
1150 | if (bootp_packet_handler) { |
1151 | ifrom.len = 4; | |
1152 | memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len); | |
1153 | ||
b1b7b521 | 1154 | (*bootp_packet_handler) (ip, &u.packet, (unsigned)result, |
fa226d8f TL |
1155 | from.sin_port, ifrom, &hfrom); |
1156 | } | |
a034015f TL |
1157 | |
1158 | /* If there is buffered data, read again. This is for, e.g., | |
1159 | bpf, which may return two packets at once. */ | |
1160 | if (ip -> rbuf_offset != ip -> rbuf_len) | |
1161 | goto again; | |
acc21512 TL |
1162 | return ISC_R_SUCCESS; |
1163 | } | |
1164 | ||
fe5b0fdd | 1165 | #ifdef DHCPv6 |
98bd7ca0 DH |
1166 | isc_result_t |
1167 | got_one_v6(omapi_object_t *h) { | |
1168 | struct sockaddr_in6 from; | |
1169 | struct in6_addr to; | |
1170 | struct iaddr ifrom; | |
1171 | int result; | |
1172 | char buf[65536]; /* maximum size for a UDP packet is 65536 */ | |
1173 | struct interface_info *ip; | |
1174 | int is_unicast; | |
ecddae64 | 1175 | unsigned int if_idx = 0; |
98bd7ca0 DH |
1176 | |
1177 | if (h->type != dhcp_type_interface) { | |
98bf1607 | 1178 | return DHCP_R_INVALIDARG; |
98bd7ca0 DH |
1179 | } |
1180 | ip = (struct interface_info *)h; | |
1181 | ||
28868515 | 1182 | result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf), |
ecddae64 | 1183 | &from, &to, &if_idx); |
98bd7ca0 DH |
1184 | if (result < 0) { |
1185 | log_error("receive_packet6() failed on %s: %m", ip->name); | |
1186 | return ISC_R_UNEXPECTED; | |
1187 | } | |
1188 | ||
ecddae64 DH |
1189 | /* 0 is 'any' interface. */ |
1190 | if (if_idx == 0) | |
1191 | return ISC_R_NOTFOUND; | |
1192 | ||
98bd7ca0 DH |
1193 | if (dhcpv6_packet_handler != NULL) { |
1194 | /* | |
1195 | * If a packet is not multicast, we assume it is unicast. | |
1196 | */ | |
1197 | if (IN6_IS_ADDR_MULTICAST(&to)) { | |
1198 | is_unicast = ISC_FALSE; | |
1199 | } else { | |
1200 | is_unicast = ISC_TRUE; | |
1201 | } | |
1202 | ||
1203 | ifrom.len = 16; | |
1204 | memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len); | |
1205 | ||
ecddae64 | 1206 | /* Seek forward to find the matching source interface. */ |
7cfeb916 | 1207 | ip = interfaces; |
ecddae64 DH |
1208 | while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx)) |
1209 | ip = ip->next; | |
1210 | ||
1211 | if (ip == NULL) | |
1212 | return ISC_R_NOTFOUND; | |
1213 | ||
98bd7ca0 DH |
1214 | (*dhcpv6_packet_handler)(ip, buf, |
1215 | result, from.sin6_port, | |
1216 | &ifrom, is_unicast); | |
1217 | } | |
1218 | ||
1219 | return ISC_R_SUCCESS; | |
1220 | } | |
fe5b0fdd | 1221 | #endif /* DHCPv6 */ |
98bd7ca0 | 1222 | |
a034015f TL |
1223 | isc_result_t dhcp_interface_set_value (omapi_object_t *h, |
1224 | omapi_object_t *id, | |
1225 | omapi_data_string_t *name, | |
1226 | omapi_typed_data_t *value) | |
acc21512 | 1227 | { |
a034015f TL |
1228 | struct interface_info *interface; |
1229 | isc_result_t status; | |
a034015f | 1230 | |
acc21512 | 1231 | if (h -> type != dhcp_type_interface) |
98bf1607 | 1232 | return DHCP_R_INVALIDARG; |
a034015f TL |
1233 | interface = (struct interface_info *)h; |
1234 | ||
1235 | if (!omapi_ds_strcmp (name, "name")) { | |
1236 | if ((value -> type == omapi_datatype_data || | |
1237 | value -> type == omapi_datatype_string) && | |
1238 | value -> u.buffer.len < sizeof interface -> name) { | |
1239 | memcpy (interface -> name, | |
1240 | value -> u.buffer.value, | |
1241 | value -> u.buffer.len); | |
1242 | interface -> name [value -> u.buffer.len] = 0; | |
1243 | } else | |
98bf1607 | 1244 | return DHCP_R_INVALIDARG; |
a034015f TL |
1245 | return ISC_R_SUCCESS; |
1246 | } | |
1247 | ||
1248 | /* Try to find some inner object that can take the value. */ | |
1249 | if (h -> inner && h -> inner -> type -> set_value) { | |
1250 | status = ((*(h -> inner -> type -> set_value)) | |
1251 | (h -> inner, id, name, value)); | |
98bf1607 | 1252 | if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED) |
a034015f TL |
1253 | return status; |
1254 | } | |
1255 | ||
acc21512 TL |
1256 | return ISC_R_NOTFOUND; |
1257 | } | |
1258 | ||
a034015f TL |
1259 | |
1260 | isc_result_t dhcp_interface_get_value (omapi_object_t *h, | |
1261 | omapi_object_t *id, | |
1262 | omapi_data_string_t *name, | |
1263 | omapi_value_t **value) | |
acc21512 | 1264 | { |
a034015f TL |
1265 | return ISC_R_NOTIMPLEMENTED; |
1266 | } | |
1267 | ||
1268 | isc_result_t dhcp_interface_destroy (omapi_object_t *h, | |
1269 | const char *file, int line) | |
1270 | { | |
1271 | struct interface_info *interface; | |
a034015f | 1272 | |
acc21512 | 1273 | if (h -> type != dhcp_type_interface) |
98bf1607 | 1274 | return DHCP_R_INVALIDARG; |
a034015f TL |
1275 | interface = (struct interface_info *)h; |
1276 | ||
d758ad8c | 1277 | if (interface -> ifp) { |
a034015f | 1278 | dfree (interface -> ifp, file, line); |
d758ad8c TL |
1279 | interface -> ifp = 0; |
1280 | } | |
1281 | if (interface -> next) | |
1282 | interface_dereference (&interface -> next, file, line); | |
1283 | if (interface -> rbuf) { | |
1284 | dfree (interface -> rbuf, file, line); | |
1285 | interface -> rbuf = (unsigned char *)0; | |
1286 | } | |
1287 | if (interface -> client) | |
1288 | interface -> client = (struct client_state *)0; | |
1289 | ||
1290 | if (interface -> shared_network) | |
1291 | omapi_object_dereference ((omapi_object_t **) | |
1292 | &interface -> shared_network, MDL); | |
1293 | ||
a034015f | 1294 | return ISC_R_SUCCESS; |
acc21512 TL |
1295 | } |
1296 | ||
a034015f TL |
1297 | isc_result_t dhcp_interface_signal_handler (omapi_object_t *h, |
1298 | const char *name, va_list ap) | |
acc21512 | 1299 | { |
a034015f | 1300 | struct interface_info *ip, *interface; |
a034015f TL |
1301 | isc_result_t status; |
1302 | ||
1303 | if (h -> type != dhcp_type_interface) | |
98bf1607 | 1304 | return DHCP_R_INVALIDARG; |
a034015f TL |
1305 | interface = (struct interface_info *)h; |
1306 | ||
cf75fef2 TL |
1307 | /* If it's an update signal, see if the interface is dead right |
1308 | now, or isn't known at all, and if that's the case, revive it. */ | |
1309 | if (!strcmp (name, "update")) { | |
1310 | for (ip = dummy_interfaces; ip; ip = ip -> next) | |
1311 | if (ip == interface) | |
1312 | break; | |
1313 | if (ip && dhcp_interface_startup_hook) | |
1314 | return (*dhcp_interface_startup_hook) (ip); | |
a034015f | 1315 | |
cf75fef2 TL |
1316 | for (ip = interfaces; ip; ip = ip -> next) |
1317 | if (ip == interface) | |
1318 | break; | |
1319 | if (!ip && dhcp_interface_startup_hook) | |
1320 | return (*dhcp_interface_startup_hook) (ip); | |
a034015f | 1321 | } |
a034015f | 1322 | |
a034015f | 1323 | /* Try to find some inner object that can take the value. */ |
875e99dc | 1324 | if (h -> inner && h -> inner -> type -> signal_handler) { |
a034015f TL |
1325 | status = ((*(h -> inner -> type -> signal_handler)) |
1326 | (h -> inner, name, ap)); | |
1327 | if (status == ISC_R_SUCCESS) | |
1328 | return status; | |
1329 | } | |
acc21512 TL |
1330 | return ISC_R_NOTFOUND; |
1331 | } | |
1332 | ||
a034015f TL |
1333 | isc_result_t dhcp_interface_stuff_values (omapi_object_t *c, |
1334 | omapi_object_t *id, | |
1335 | omapi_object_t *h) | |
acc21512 | 1336 | { |
a034015f TL |
1337 | struct interface_info *interface; |
1338 | isc_result_t status; | |
acc21512 | 1339 | |
acc21512 | 1340 | if (h -> type != dhcp_type_interface) |
98bf1607 | 1341 | return DHCP_R_INVALIDARG; |
a034015f TL |
1342 | interface = (struct interface_info *)h; |
1343 | ||
1344 | /* Write out all the values. */ | |
1345 | ||
1346 | status = omapi_connection_put_name (c, "state"); | |
1347 | if (status != ISC_R_SUCCESS) | |
1348 | return status; | |
c1e6c832 | 1349 | if ((interface->flags & INTERFACE_REQUESTED) != 0) |
a034015f TL |
1350 | status = omapi_connection_put_string (c, "up"); |
1351 | else | |
1352 | status = omapi_connection_put_string (c, "down"); | |
1353 | if (status != ISC_R_SUCCESS) | |
1354 | return status; | |
1355 | ||
1356 | /* Write out the inner object, if any. */ | |
1357 | if (h -> inner && h -> inner -> type -> stuff_values) { | |
1358 | status = ((*(h -> inner -> type -> stuff_values)) | |
1359 | (c, id, h -> inner)); | |
1360 | if (status == ISC_R_SUCCESS) | |
1361 | return status; | |
1362 | } | |
1363 | ||
acc21512 TL |
1364 | return ISC_R_SUCCESS; |
1365 | } | |
1366 | ||
a034015f TL |
1367 | isc_result_t dhcp_interface_lookup (omapi_object_t **ip, |
1368 | omapi_object_t *id, | |
1369 | omapi_object_t *ref) | |
acc21512 | 1370 | { |
a034015f TL |
1371 | omapi_value_t *tv = (omapi_value_t *)0; |
1372 | isc_result_t status; | |
1373 | struct interface_info *interface; | |
1374 | ||
d758ad8c | 1375 | if (!ref) |
98bf1607 | 1376 | return DHCP_R_NOKEYS; |
d758ad8c | 1377 | |
a034015f TL |
1378 | /* First see if we were sent a handle. */ |
1379 | status = omapi_get_value_str (ref, id, "handle", &tv); | |
1380 | if (status == ISC_R_SUCCESS) { | |
1381 | status = omapi_handle_td_lookup (ip, tv -> value); | |
1382 | ||
1383 | omapi_value_dereference (&tv, MDL); | |
1384 | if (status != ISC_R_SUCCESS) | |
1385 | return status; | |
1386 | ||
1387 | /* Don't return the object if the type is wrong. */ | |
1388 | if ((*ip) -> type != dhcp_type_interface) { | |
1389 | omapi_object_dereference (ip, MDL); | |
98bf1607 | 1390 | return DHCP_R_INVALIDARG; |
a034015f TL |
1391 | } |
1392 | } | |
1393 | ||
1394 | /* Now look for an interface name. */ | |
1395 | status = omapi_get_value_str (ref, id, "name", &tv); | |
1396 | if (status == ISC_R_SUCCESS) { | |
cf75fef2 TL |
1397 | char *s; |
1398 | unsigned len; | |
a034015f TL |
1399 | for (interface = interfaces; interface; |
1400 | interface = interface -> next) { | |
cf75fef2 TL |
1401 | s = memchr (interface -> name, 0, IFNAMSIZ); |
1402 | if (s) | |
1403 | len = s - &interface -> name [0]; | |
1404 | else | |
1405 | len = IFNAMSIZ; | |
1406 | if ((tv -> value -> u.buffer.len == len && | |
1407 | !memcmp (interface -> name, | |
1408 | (char *)tv -> value -> u.buffer.value, | |
1409 | len))) | |
a034015f TL |
1410 | break; |
1411 | } | |
cf75fef2 TL |
1412 | if (!interface) { |
1413 | for (interface = dummy_interfaces; | |
1414 | interface; interface = interface -> next) { | |
1415 | s = memchr (interface -> name, 0, IFNAMSIZ); | |
1416 | if (s) | |
1417 | len = s - &interface -> name [0]; | |
1418 | else | |
1419 | len = IFNAMSIZ; | |
1420 | if ((tv -> value -> u.buffer.len == len && | |
1421 | !memcmp (interface -> name, | |
1422 | (char *) | |
1423 | tv -> value -> u.buffer.value, | |
1424 | len))) | |
1425 | break; | |
1426 | } | |
1427 | } | |
1428 | ||
a034015f TL |
1429 | omapi_value_dereference (&tv, MDL); |
1430 | if (*ip && *ip != (omapi_object_t *)interface) { | |
1431 | omapi_object_dereference (ip, MDL); | |
98bf1607 | 1432 | return DHCP_R_KEYCONFLICT; |
a034015f TL |
1433 | } else if (!interface) { |
1434 | if (*ip) | |
1435 | omapi_object_dereference (ip, MDL); | |
1436 | return ISC_R_NOTFOUND; | |
1437 | } else if (!*ip) | |
a034015f TL |
1438 | omapi_object_reference (ip, |
1439 | (omapi_object_t *)interface, | |
1440 | MDL); | |
1441 | } | |
1442 | ||
1443 | /* If we get to here without finding an interface, no valid key was | |
1444 | specified. */ | |
1445 | if (!*ip) | |
98bf1607 | 1446 | return DHCP_R_NOKEYS; |
a034015f TL |
1447 | return ISC_R_SUCCESS; |
1448 | } | |
1449 | ||
1450 | /* actually just go discover the interface */ | |
1451 | isc_result_t dhcp_interface_create (omapi_object_t **lp, | |
1452 | omapi_object_t *id) | |
1453 | { | |
1454 | struct interface_info *hp; | |
1455 | isc_result_t status; | |
acc21512 | 1456 | |
a034015f TL |
1457 | hp = (struct interface_info *)0; |
1458 | status = interface_allocate (&hp, MDL); | |
1459 | if (status != ISC_R_SUCCESS) | |
1460 | return status; | |
1461 | hp -> flags = INTERFACE_REQUESTED; | |
1462 | status = interface_reference ((struct interface_info **)lp, hp, MDL); | |
1463 | interface_dereference (&hp, MDL); | |
1464 | return status; | |
fa226d8f TL |
1465 | } |
1466 | ||
a034015f TL |
1467 | isc_result_t dhcp_interface_remove (omapi_object_t *lp, |
1468 | omapi_object_t *id) | |
1469 | { | |
1470 | struct interface_info *interface, *ip, *last; | |
1471 | ||
1472 | interface = (struct interface_info *)lp; | |
1473 | ||
1474 | /* remove from interfaces */ | |
1475 | last = 0; | |
1476 | for (ip = interfaces; ip; ip = ip -> next) { | |
1477 | if (ip == interface) { | |
1478 | if (last) { | |
1479 | interface_dereference (&last -> next, MDL); | |
1480 | if (ip -> next) | |
1481 | interface_reference (&last -> next, | |
1482 | ip -> next, MDL); | |
1483 | } else { | |
1484 | interface_dereference (&interfaces, MDL); | |
1485 | if (ip -> next) | |
1486 | interface_reference (&interfaces, | |
1487 | ip -> next, MDL); | |
1488 | } | |
1489 | if (ip -> next) | |
1490 | interface_dereference (&ip -> next, MDL); | |
1491 | break; | |
1492 | } | |
1493 | last = ip; | |
1494 | } | |
1495 | if (!ip) | |
1496 | return ISC_R_NOTFOUND; | |
1497 | ||
1498 | /* add the interface to the dummy_interface list */ | |
1499 | if (dummy_interfaces) { | |
1500 | interface_reference (&interface -> next, | |
1501 | dummy_interfaces, MDL); | |
1502 | interface_dereference (&dummy_interfaces, MDL); | |
1503 | } | |
1504 | interface_reference (&dummy_interfaces, interface, MDL); | |
1505 | ||
1506 | /* do a DHCPRELEASE */ | |
1507 | if (dhcp_interface_shutdown_hook) | |
1508 | (*dhcp_interface_shutdown_hook) (interface); | |
1509 | ||
1510 | /* remove the io object */ | |
1511 | omapi_unregister_io_object ((omapi_object_t *)interface); | |
1512 | ||
98bf1607 | 1513 | switch(local_family) { |
fe5b0fdd | 1514 | #ifdef DHCPv6 |
98bf1607 | 1515 | case AF_INET6: |
98bd7ca0 | 1516 | if_deregister6(interface); |
98bf1607 | 1517 | break; |
fe5b0fdd | 1518 | #endif /* DHCPv6 */ |
98bf1607 SR |
1519 | case AF_INET: |
1520 | default: | |
1521 | if_deregister_send(interface); | |
1522 | if_deregister_receive(interface); | |
1523 | break; | |
98bd7ca0 | 1524 | } |
a034015f TL |
1525 | |
1526 | return ISC_R_SUCCESS; | |
1527 | } | |
fc33f8c5 TL |
1528 | |
1529 | void interface_stash (struct interface_info *tptr) | |
1530 | { | |
1531 | struct interface_info **vec; | |
1532 | int delta; | |
1533 | ||
1534 | /* If the registerer didn't assign an index, assign one now. */ | |
1535 | if (tptr -> index == -1) { | |
1536 | tptr -> index = interface_count++; | |
1537 | while (tptr -> index < interface_max && | |
1538 | interface_vector [tptr -> index]) | |
1539 | tptr -> index = interface_count++; | |
1540 | } | |
1541 | ||
1542 | if (interface_max <= tptr -> index) { | |
1543 | delta = tptr -> index - interface_max + 10; | |
1544 | vec = dmalloc ((interface_max + delta) * | |
1545 | sizeof (struct interface_info *), MDL); | |
8c785e79 TM |
1546 | if (!vec) { |
1547 | log_error ("interface_stash: allocation failed "); | |
fc33f8c5 | 1548 | return; |
8c785e79 TM |
1549 | } |
1550 | ||
fc33f8c5 TL |
1551 | memset (&vec [interface_max], 0, |
1552 | (sizeof (struct interface_info *)) * delta); | |
1553 | interface_max += delta; | |
1554 | if (interface_vector) { | |
1555 | memcpy (vec, interface_vector, | |
1556 | (interface_count * | |
1557 | sizeof (struct interface_info *))); | |
1558 | dfree (interface_vector, MDL); | |
1559 | } | |
8c785e79 | 1560 | |
fc33f8c5 TL |
1561 | interface_vector = vec; |
1562 | } | |
8c785e79 | 1563 | |
d758ad8c | 1564 | interface_reference (&interface_vector [tptr -> index], tptr, MDL); |
fc33f8c5 TL |
1565 | if (tptr -> index >= interface_count) |
1566 | interface_count = tptr -> index + 1; | |
1567 | #if defined (TRACING) | |
1568 | trace_interface_register (interface_trace, tptr); | |
1569 | #endif | |
1570 | } | |
1571 | ||
1572 | void interface_snorf (struct interface_info *tmp, int ir) | |
1573 | { | |
1574 | tmp -> circuit_id = (u_int8_t *)tmp -> name; | |
1575 | tmp -> circuit_id_len = strlen (tmp -> name); | |
1576 | tmp -> remote_id = 0; | |
1577 | tmp -> remote_id_len = 0; | |
1578 | tmp -> flags = ir; | |
1579 | if (interfaces) { | |
1580 | interface_reference (&tmp -> next, | |
1581 | interfaces, MDL); | |
1582 | interface_dereference (&interfaces, MDL); | |
1583 | } | |
1584 | interface_reference (&interfaces, tmp, MDL); | |
1585 | } |