discover.c revision 1.1 1 /* $NetBSD: discover.c,v 1.1 2018/04/07 22:34:25 christos Exp $ */
2
3 /* discover.c
4
5 Find and identify the network interfaces. */
6
7 /*
8 * Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1995-2003 by Internet Software Consortium
10 *
11 * This Source Code Form is subject to the terms of the Mozilla Public
12 * License, v. 2.0. If a copy of the MPL was not distributed with this
13 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
16 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
18 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 *
23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street
25 * Redwood City, CA 94063
26 * <info (at) isc.org>
27 * https://www.isc.org/
28 *
29 */
30
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: discover.c,v 1.1 2018/04/07 22:34:25 christos Exp $");
33
34 #include "dhcpd.h"
35
36 /* length of line we can read from the IF file, 256 is too small in some cases */
37 #define IF_LINE_LENGTH 1024
38
39 #define BSD_COMP /* needed on Solaris for SIOCGLIFNUM */
40 #include <sys/ioctl.h>
41 #include <errno.h>
42
43 #ifdef HAVE_NET_IF6_H
44 # include <net/if6.h>
45 #endif
46
47 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
48 int interfaces_invalidated;
49 int quiet_interface_discovery;
50 u_int16_t local_port;
51 u_int16_t remote_port;
52 u_int16_t relay_port = 0;
53 int dhcpv4_over_dhcpv6 = 0;
54 int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
55 int (*dhcp_interface_discovery_hook) (struct interface_info *);
56 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
57 int (*dhcp_interface_shutdown_hook) (struct interface_info *);
58
59 struct in_addr limited_broadcast;
60
61 int local_family = AF_INET;
62 struct in_addr local_address;
63
64 #ifdef DHCPv6
65 /*
66 * Another clear abuse of the fact that undefined IP addresses are all zeroes.
67 */
68 struct in6_addr local_address6;
69 int bind_local_address6 = 0;
70 #endif /* DHCPv6 */
71
72 void (*bootp_packet_handler) (struct interface_info *,
73 struct dhcp_packet *, unsigned,
74 unsigned int,
75 struct iaddr, struct hardware *);
76
77 #ifdef DHCPv6
78 void (*dhcpv6_packet_handler)(struct interface_info *,
79 const char *, int,
80 int, const struct iaddr *,
81 isc_boolean_t);
82 #endif /* DHCPv6 */
83
84
85 omapi_object_type_t *dhcp_type_interface;
86 #if defined (TRACING)
87 trace_type_t *interface_trace;
88 trace_type_t *inpacket_trace;
89 trace_type_t *outpacket_trace;
90 #endif
91 struct interface_info **interface_vector;
92 int interface_count;
93 int interface_max;
94
95 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
96
97 isc_result_t interface_setup ()
98 {
99 isc_result_t status;
100 status = omapi_object_type_register (&dhcp_type_interface,
101 "interface",
102 dhcp_interface_set_value,
103 dhcp_interface_get_value,
104 dhcp_interface_destroy,
105 dhcp_interface_signal_handler,
106 dhcp_interface_stuff_values,
107 dhcp_interface_lookup,
108 dhcp_interface_create,
109 dhcp_interface_remove,
110 0, 0, 0,
111 sizeof (struct interface_info),
112 interface_initialize, RC_MISC);
113 if (status != ISC_R_SUCCESS)
114 log_fatal ("Can't register interface object type: %s",
115 isc_result_totext (status));
116
117 return status;
118 }
119
120 #if defined (TRACING)
121 void interface_trace_setup ()
122 {
123 interface_trace = trace_type_register ("interface", (void *)0,
124 trace_interface_input,
125 trace_interface_stop, MDL);
126 inpacket_trace = trace_type_register ("inpacket", (void *)0,
127 trace_inpacket_input,
128 trace_inpacket_stop, MDL);
129 outpacket_trace = trace_type_register ("outpacket", (void *)0,
130 trace_outpacket_input,
131 trace_outpacket_stop, MDL);
132 }
133 #endif
134
135 isc_result_t interface_initialize (omapi_object_t *ipo,
136 const char *file, int line)
137 {
138 struct interface_info *ip = (struct interface_info *)ipo;
139 ip -> rfdesc = ip -> wfdesc = -1;
140 return ISC_R_SUCCESS;
141 }
142
143
144 /*
145 * Scanning for Interfaces
146 * -----------------------
147 *
148 * To find interfaces, we create an iterator that abstracts out most
149 * of the platform specifics. Use is fairly straightforward:
150 *
151 * - begin_iface_scan() starts the process.
152 * - Use next_iface() until it returns 0.
153 * - end_iface_scan() performs any necessary cleanup.
154 *
155 * We check for errors on each call to next_iface(), which returns a
156 * description of the error as a string if any occurs.
157 *
158 * We currently have code for Solaris and Linux. Other systems need
159 * to have code written.
160 *
161 * NOTE: the long-term goal is to use the interface code from BIND 9.
162 */
163
164 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && defined(SIOCGLIFFLAGS)
165
166 /* HP/UX doesn't define struct lifconf, instead they define struct
167 * if_laddrconf. Similarly, 'struct lifreq' and 'struct lifaddrreq'.
168 */
169 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
170 # define lifc_len iflc_len
171 # define lifc_buf iflc_buf
172 # define lifc_req iflc_req
173 # define LIFCONF if_laddrconf
174 #else
175 # define ISC_HAVE_LIFC_FAMILY 1
176 # define ISC_HAVE_LIFC_FLAGS 1
177 # define LIFCONF lifconf
178 #endif
179
180 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
181 # define lifr_addr iflr_addr
182 # define lifr_name iflr_name
183 # define lifr_dstaddr iflr_dstaddr
184 # define lifr_flags iflr_flags
185 # define sockaddr_storage sockaddr_ext
186 # define ss_family sa_family
187 # define LIFREQ if_laddrreq
188 #else
189 # define LIFREQ lifreq
190 #endif
191
192 #ifndef IF_NAMESIZE
193 # if defined(LIFNAMSIZ)
194 # define IF_NAMESIZE LIFNAMSIZ
195 # elif defined(IFNAMSIZ)
196 # define IF_NAMESIZE IFNAMSIZ
197 # else
198 # define IF_NAMESIZE 16
199 # endif
200 #endif
201 #elif !defined(__linux) && !defined(HAVE_IFADDRS_H)
202 # define SIOCGLIFCONF SIOCGIFCONF
203 # define SIOCGLIFFLAGS SIOCGIFFLAGS
204 # define LIFREQ ifreq
205 # define LIFCONF ifconf
206 # define lifr_name ifr_name
207 # define lifr_addr ifr_addr
208 # define lifr_flags ifr_flags
209 # define lifc_len ifc_len
210 # define lifc_buf ifc_buf
211 # define lifc_req ifc_req
212 #ifdef _AIX
213 # define ss_family __ss_family
214 #endif
215 #endif
216
217 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
218 /*
219 * Solaris support
220 * ---------------
221 *
222 * The SIOCGLIFCONF ioctl() are the extension that you need to use
223 * on Solaris to get information about IPv6 addresses.
224 *
225 * Solaris' extended interface is documented in the if_tcp man page.
226 */
227
228 /*
229 * Structure holding state about the scan.
230 */
231 struct iface_conf_list {
232 int sock; /* file descriptor used to get information */
233 int num; /* total number of interfaces */
234 struct LIFCONF conf; /* structure used to get information */
235 int next; /* next interface to retrieve when iterating */
236 };
237
238 /*
239 * Structure used to return information about a specific interface.
240 */
241 struct iface_info {
242 char name[IF_NAMESIZE+1]; /* name of the interface, e.g. "bge0" */
243 struct sockaddr_storage addr; /* address information */
244 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
245 };
246
247 /*
248 * Start a scan of interfaces.
249 *
250 * The iface_conf_list structure maintains state for this process.
251 */
252 int
253 begin_iface_scan(struct iface_conf_list *ifaces) {
254 #ifdef ISC_PLATFORM_HAVELIFNUM
255 struct lifnum lifnum;
256 #else
257 int lifnum;
258 #endif
259
260 ifaces->sock = socket(local_family, SOCK_DGRAM, IPPROTO_UDP);
261 if (ifaces->sock < 0) {
262 log_error("Error creating socket to list interfaces; %m");
263 return 0;
264 }
265
266 memset(&lifnum, 0, sizeof(lifnum));
267 #ifdef ISC_PLATFORM_HAVELIFNUM
268 lifnum.lifn_family = AF_UNSPEC;
269 #endif
270 #ifdef SIOCGLIFNUM
271 if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) {
272 log_error("Error finding total number of interfaces; %m");
273 close(ifaces->sock);
274 ifaces->sock = -1;
275 return 0;
276 }
277
278 #ifdef ISC_PLATFORM_HAVELIFNUM
279 ifaces->num = lifnum.lifn_count;
280 #else
281 ifaces->num = lifnum;
282 #endif
283 #else
284 ifaces->num = 64;
285 #endif /* SIOCGLIFNUM */
286
287 memset(&ifaces->conf, 0, sizeof(ifaces->conf));
288 #ifdef ISC_HAVE_LIFC_FAMILY
289 ifaces->conf.lifc_family = AF_UNSPEC;
290 #endif
291 ifaces->conf.lifc_len = ifaces->num * sizeof(struct LIFREQ);
292 ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL);
293 if (ifaces->conf.lifc_buf == NULL) {
294 log_fatal("Out of memory getting interface list.");
295 }
296
297 if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) {
298 log_error("Error getting interfaces configuration list; %m");
299 dfree(ifaces->conf.lifc_buf, MDL);
300 close(ifaces->sock);
301 ifaces->sock = -1;
302 return 0;
303 }
304
305 ifaces->next = 0;
306
307 return 1;
308 }
309
310 /*
311 * Retrieve the next interface.
312 *
313 * Returns information in the info structure.
314 * Sets err to 1 if there is an error, otherwise 0.
315 */
316 int
317 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
318 struct LIFREQ *p;
319 struct LIFREQ tmp;
320 isc_boolean_t foundif;
321 #if defined(sun) || defined(__linux)
322 /* Pointer used to remove interface aliases. */
323 char *s;
324 #endif
325
326 do {
327 foundif = ISC_FALSE;
328
329 if (ifaces->next >= ifaces->num) {
330 *err = 0;
331 return 0;
332 }
333
334 p = ifaces->conf.lifc_req;
335 p += ifaces->next;
336
337 if (strlen(p->lifr_name) >= sizeof(info->name)) {
338 *err = 1;
339 log_error("Interface name '%s' too long", p->lifr_name);
340 return 0;
341 }
342
343 /* Reject if interface address family does not match */
344 if (p->lifr_addr.ss_family != local_family) {
345 ifaces->next++;
346 continue;
347 }
348
349 memset(info, 0, sizeof(struct iface_info));
350 strncpy(info->name, p->lifr_name, sizeof(info->name) - 1);
351 memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr));
352
353 #if defined(sun) || defined(__linux)
354 /* interface aliases look like "eth0:1" or "wlan1:3" */
355 s = strchr(info->name, ':');
356 if (s != NULL) {
357 *s = '\0';
358 }
359 #endif /* defined(sun) || defined(__linux) */
360
361 foundif = ISC_TRUE;
362 } while ((foundif == ISC_FALSE) ||
363 (strncmp(info->name, "dummy", 5) == 0));
364
365 memset(&tmp, 0, sizeof(tmp));
366 strncpy(tmp.lifr_name, info->name, sizeof(tmp.lifr_name) - 1);
367 if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) {
368 log_error("Error getting interface flags for '%s'; %m",
369 p->lifr_name);
370 *err = 1;
371 return 0;
372 }
373 info->flags = tmp.lifr_flags;
374
375 ifaces->next++;
376 *err = 0;
377 return 1;
378 }
379
380 /*
381 * End scan of interfaces.
382 */
383 void
384 end_iface_scan(struct iface_conf_list *ifaces) {
385 dfree(ifaces->conf.lifc_buf, MDL);
386 close(ifaces->sock);
387 ifaces->sock = -1;
388 }
389
390 #else
391
392 /*
393 * BSD/Linux support
394 * -----------
395 *
396 * FreeBSD, NetBSD, OpenBSD, OS X/macOS and Linux all have the getifaddrs()
397 * function.
398 *
399 * The getifaddrs() man page describes the use.
400 */
401
402 #include <ifaddrs.h>
403
404 /*
405 * Structure holding state about the scan.
406 */
407 struct iface_conf_list {
408 struct ifaddrs *head; /* beginning of the list */
409 struct ifaddrs *next; /* current position in the list */
410 };
411
412 /*
413 * Structure used to return information about a specific interface.
414 */
415 struct iface_info {
416 char name[IFNAMSIZ]; /* name of the interface, e.g. "bge0" */
417 struct sockaddr_storage addr; /* address information */
418 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
419 };
420
421 /*
422 * Start a scan of interfaces.
423 *
424 * The iface_conf_list structure maintains state for this process.
425 */
426 int
427 begin_iface_scan(struct iface_conf_list *ifaces) {
428 if (getifaddrs(&ifaces->head) != 0) {
429 log_error("Error getting interfaces; %m");
430 return 0;
431 }
432 ifaces->next = ifaces->head;
433 return 1;
434 }
435
436 /*
437 * Retrieve the next interface.
438 *
439 * Returns information in the info structure.
440 * Sets err to 1 if there is an error, otherwise 0.
441 */
442 int
443 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
444 size_t sa_len = 0;
445
446 if (ifaces->next == NULL) {
447 *err = 0;
448 return 0;
449 }
450 if (strlen(ifaces->next->ifa_name) >= sizeof(info->name)) {
451 log_error("Interface name '%s' too long",
452 ifaces->next->ifa_name);
453 *err = 1;
454 return 0;
455 }
456 memset(info, 0, sizeof(struct iface_info));
457 strncpy(info->name, ifaces->next->ifa_name, sizeof(info->name) - 1);
458 memset(&info->addr, 0 , sizeof(info->addr));
459 /*
460 * getifaddrs() can on Linux with some interfaces like PPP or TEQL
461 * result in a record with no address (ifa_addr).
462 */
463 if (ifaces->next->ifa_addr != NULL) {
464 /* Linux lacks the sa_len member in struct sockaddr. */
465 #if defined(__linux)
466 if (ifaces->next->ifa_addr->sa_family == AF_INET)
467 sa_len = sizeof(struct sockaddr_in);
468 else if (ifaces->next->ifa_addr->sa_family == AF_INET6)
469 sa_len = sizeof(struct sockaddr_in6);
470 #else
471 sa_len = ifaces->next->ifa_addr->sa_len;
472 #endif
473 memcpy(&info->addr, ifaces->next->ifa_addr, sa_len);
474 }
475 info->flags = ifaces->next->ifa_flags;
476 ifaces->next = ifaces->next->ifa_next;
477 *err = 0;
478 return 1;
479 }
480
481 /*
482 * End scan of interfaces.
483 */
484 void
485 end_iface_scan(struct iface_conf_list *ifaces) {
486 freeifaddrs(ifaces->head);
487 ifaces->head = NULL;
488 ifaces->next = NULL;
489 }
490 #endif
491
492 /* XXX: perhaps create drealloc() rather than do it manually */
493 void
494 add_ipv4_addr_to_interface(struct interface_info *iface,
495 const struct in_addr *addr) {
496 /*
497 * We don't expect a lot of addresses per IPv4 interface, so
498 * we use 4, as our "chunk size" for collecting addresses.
499 */
500 if (iface->addresses == NULL) {
501 iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL);
502 if (iface->addresses == NULL) {
503 log_fatal("Out of memory saving IPv4 address "
504 "on interface.");
505 }
506 iface->address_count = 0;
507 iface->address_max = 4;
508 } else if (iface->address_count >= iface->address_max) {
509 struct in_addr *tmp;
510 int new_max;
511
512 new_max = iface->address_max + 4;
513 tmp = dmalloc(new_max * sizeof(struct in_addr), MDL);
514 if (tmp == NULL) {
515 log_fatal("Out of memory saving IPv4 address "
516 "on interface.");
517 }
518 memcpy(tmp,
519 iface->addresses,
520 iface->address_max * sizeof(struct in_addr));
521 dfree(iface->addresses, MDL);
522 iface->addresses = tmp;
523 iface->address_max = new_max;
524 }
525 iface->addresses[iface->address_count++] = *addr;
526 }
527
528 #ifdef DHCPv6
529 /* XXX: perhaps create drealloc() rather than do it manually */
530 void
531 add_ipv6_addr_to_interface(struct interface_info *iface,
532 const struct in6_addr *addr) {
533 /*
534 * Each IPv6 interface will have at least two IPv6 addresses,
535 * and likely quite a few more. So we use 8, as our "chunk size" for
536 * collecting addresses.
537 */
538 if (iface->v6addresses == NULL) {
539 iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL);
540 if (iface->v6addresses == NULL) {
541 log_fatal("Out of memory saving IPv6 address "
542 "on interface.");
543 }
544 iface->v6address_count = 0;
545 iface->v6address_max = 8;
546 } else if (iface->v6address_count >= iface->v6address_max) {
547 struct in6_addr *tmp;
548 int new_max;
549
550 new_max = iface->v6address_max + 8;
551 tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL);
552 if (tmp == NULL) {
553 log_fatal("Out of memory saving IPv6 address "
554 "on interface.");
555 }
556 memcpy(tmp,
557 iface->v6addresses,
558 iface->v6address_max * sizeof(struct in6_addr));
559 dfree(iface->v6addresses, MDL);
560 iface->v6addresses = tmp;
561 iface->v6address_max = new_max;
562 }
563 iface->v6addresses[iface->v6address_count++] = *addr;
564 }
565 #endif /* DHCPv6 */
566
567 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
568 For each interface that's of type INET and not the loopback interface,
569 register that interface with the network I/O software, figure out what
570 subnet it's on, and add it to the list of interfaces. */
571
572 void
573 discover_interfaces(int state) {
574 struct iface_conf_list ifaces;
575 struct iface_info info;
576 int err;
577
578 struct interface_info *tmp;
579 struct interface_info *last, *next;
580
581 #ifdef DHCPv6
582 char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
583 #endif /* DHCPv6 */
584
585
586 struct subnet *subnet;
587 int ir;
588 isc_result_t status;
589 int wifcount = 0;
590 #ifdef RELAY_PORT
591 int updone = 0;
592 int downdone = 0;
593 #endif
594
595 static int setup_fallback = 0;
596
597 if (!begin_iface_scan(&ifaces)) {
598 log_fatal("Can't get list of interfaces.");
599 }
600
601 /* If we already have a list of interfaces, and we're running as
602 a DHCP server, the interfaces were requested. */
603 if (interfaces && (state == DISCOVER_SERVER ||
604 state == DISCOVER_RELAY ||
605 state == DISCOVER_REQUESTED))
606 ir = 0;
607 else if (state == DISCOVER_UNCONFIGURED)
608 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
609 else {
610 ir = INTERFACE_REQUESTED;
611 if (state == DISCOVER_RELAY && local_family == AF_INET) {
612 /* We're a v4 relay without specifically requested
613 * interfaces, so mark them all as bidirectional. */
614 ir |= INTERFACE_STREAMS;
615 }
616 }
617
618 /* Cycle through the list of interfaces looking for IP addresses. */
619 while (next_iface(&info, &err, &ifaces)) {
620
621 /* See if we've seen an interface that matches this one. */
622 for (tmp = interfaces; tmp; tmp = tmp->next) {
623 if (!strcmp(tmp->name, info.name))
624 break;
625 }
626
627 /* Skip non broadcast interfaces (plus loopback and
628 point-to-point in case an OS incorrectly marks them
629 as broadcast). Also skip down interfaces unless we're
630 trying to get a list of configurable interfaces. */
631 if ((((local_family == AF_INET &&
632 !(info.flags & IFF_BROADCAST)) ||
633 #ifdef DHCPv6
634 (local_family == AF_INET6 &&
635 !(info.flags & IFF_MULTICAST)) ||
636 #endif
637 info.flags & IFF_LOOPBACK ||
638 info.flags & IFF_POINTOPOINT) && !tmp) ||
639 (!(info.flags & IFF_UP) &&
640 state != DISCOVER_UNCONFIGURED))
641 continue;
642
643 /* If there isn't already an interface by this name,
644 allocate one. */
645 if (tmp == NULL) {
646 status = interface_allocate(&tmp, MDL);
647 if (status != ISC_R_SUCCESS) {
648 log_fatal("Error allocating interface %s: %s",
649 info.name, isc_result_totext(status));
650 }
651 strncpy(tmp->name, info.name, sizeof(tmp->name) - 1);
652 interface_snorf(tmp, ir);
653 interface_dereference(&tmp, MDL);
654 tmp = interfaces; /* XXX */
655 }
656
657 if (dhcp_interface_discovery_hook) {
658 (*dhcp_interface_discovery_hook)(tmp);
659 }
660
661 if ((info.addr.ss_family == AF_INET) &&
662 (local_family == AF_INET)) {
663 struct sockaddr_in *a = (struct sockaddr_in*)&info.addr;
664 struct iaddr addr;
665
666 /* We don't want the loopback interface. */
667 if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) &&
668 ((tmp->flags & INTERFACE_AUTOMATIC) &&
669 ((state == DISCOVER_SERVER) ||
670 (state == DISCOVER_SERVER46))))
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
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 }
687 #ifdef DHCPv6
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;
693
694 /* We don't want the loopback interface. */
695 if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) &&
696 ((tmp->flags & INTERFACE_AUTOMATIC) &&
697 ((state == DISCOVER_SERVER) ||
698 (state == DISCOVER_SERVER46))))
699 continue;
700
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;
705
706 add_ipv6_addr_to_interface(tmp, &a->sin6_addr);
707
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 }
714 }
715 #endif /* DHCPv6 */
716 }
717
718 if (err) {
719 log_fatal("Error getting interface information.");
720 }
721
722 end_iface_scan(&ifaces);
723
724
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
743 /* If we're just trying to get a list of interfaces that we might
744 be able to configure, we can quit now. */
745 if (state == DISCOVER_UNCONFIGURED) {
746 return;
747 }
748
749 /* Weed out the interfaces that did not have IP addresses. */
750 tmp = last = next = NULL;
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);
758 /* skip interfaces that are running already */
759 if (tmp -> flags & INTERFACE_RUNNING) {
760 interface_dereference(&tmp, MDL);
761 if(next)
762 interface_reference(&tmp, next, MDL);
763 continue;
764 }
765 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
766 state == DISCOVER_REQUESTED)
767 tmp -> flags &= ~(INTERFACE_AUTOMATIC |
768 INTERFACE_REQUESTED);
769
770 #ifdef DHCPv6
771 if (!(tmp->flags & INTERFACE_REQUESTED)) {
772 #else
773 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
774 #endif /* DHCPv6 */
775 if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
776 log_fatal ("%s: not found", tmp -> name);
777 if (!last) {
778 if (interfaces)
779 interface_dereference (&interfaces,
780 MDL);
781 if (next)
782 interface_reference (&interfaces, next, MDL);
783 } else {
784 interface_dereference (&last -> next, MDL);
785 if (next)
786 interface_reference (&last -> next,
787 next, MDL);
788 }
789 if (tmp -> next)
790 interface_dereference (&tmp -> next, MDL);
791
792 /* Remember the interface in case we need to know
793 about it later. */
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);
803 continue;
804 }
805 last = tmp;
806
807 /* We must have a subnet declaration for each interface. */
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,
813 (tmp->addresses == NULL) ?
814 "no IPv4 addresses" :
815 inet_ntoa(tmp->addresses[0]));
816 #ifdef DHCPv6
817 } else {
818 if (tmp->v6addresses != NULL) {
819 inet_ntop(AF_INET6,
820 &tmp->v6addresses[0],
821 abuf,
822 sizeof(abuf));
823 } else {
824 strcpy(abuf, "no IPv6 addresses");
825 }
826 log_error("No subnet6 declaration for %s (%s).",
827 tmp->name,
828 abuf);
829 #endif /* DHCPv6 */
830 }
831 if (supports_multiple_interfaces(tmp)) {
832 log_error ("** Ignoring requests on %s. %s",
833 tmp -> name, "If this is not what");
834 log_error (" you want, please write %s",
835 #ifdef DHCPv6
836 (local_family != AF_INET) ?
837 "a subnet6 declaration" :
838 #endif
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",
843 "which interface",
844 tmp -> name, "is attached. **");
845 log_error ("%s", "");
846 goto next;
847 } else {
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");
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 }
861 }
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) {
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 }
887 }
888 }
889
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
894 /* Register the interface... */
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;
905 #ifdef DHCPv6
906 case AF_INET6:
907 if ((state == DISCOVER_SERVER) ||
908 (state == DISCOVER_RELAY)) {
909 if_register6(tmp, 1);
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);
916 } else {
917 if_register_linklocal6(tmp);
918 }
919 break;
920 #endif /* DHCPv6 */
921 }
922
923 interface_stash (tmp);
924 wifcount++;
925 #if defined (F_SETFD)
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))
935 log_error ("Can't set close-on-exec on %s: %m",
936 tmp -> name);
937 #endif
938 next:
939 interface_dereference (&tmp, MDL);
940 if (next)
941 interface_reference (&tmp, next, MDL);
942 }
943
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 */
950 for (tmp = interfaces; tmp; tmp = tmp -> next) {
951 /* not if it's been registered before */
952 if (tmp -> flags & INTERFACE_RUNNING)
953 continue;
954 if (tmp -> rfdesc == -1)
955 continue;
956 switch (local_family) {
957 #ifdef DHCPv6
958 case AF_INET6:
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
983 status = omapi_register_io_object((omapi_object_t *)tmp,
984 if_readsocket,
985 0, got_one_v6, 0, 0);
986 #ifdef RELAY_PORT
987 if (UPSTREAM(tmp))
988 updone++;
989 else
990 downdone++;
991 #endif
992 break;
993 #endif /* DHCPv6 */
994 case AF_INET:
995 default:
996 status = omapi_register_io_object((omapi_object_t *)tmp,
997 if_readsocket,
998 0, got_one, 0, 0);
999 break;
1000 }
1001
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));
1005
1006 #if defined(DHCPv6)
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.
1012 */
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 )
1019 break;
1020 #endif
1021 } /* for (tmp = interfaces; ... */
1022
1023 if (state == DISCOVER_SERVER && wifcount == 0) {
1024 log_info ("%s", "");
1025 log_fatal ("Not configured to listen on any interfaces!");
1026 }
1027
1028 if ((local_family == AF_INET) &&
1029 !setup_fallback && !dhcpv4_over_dhcpv6) {
1030 setup_fallback = 1;
1031 maybe_setup_fallback();
1032 }
1033
1034 #if defined (F_SETFD)
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 }
1043 #endif /* F_SETFD */
1044 }
1045
1046 int if_readsocket (h)
1047 omapi_object_t *h;
1048 {
1049 struct interface_info *ip;
1050
1051 if (h -> type != dhcp_type_interface)
1052 return -1;
1053 ip = (struct interface_info *)h;
1054 return ip -> rfdesc;
1055 }
1056
1057 int setup_fallback (struct interface_info **fp, const char *file, int line)
1058 {
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));
1065 strcpy (fallback_interface -> name, "fallback");
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);
1070
1071 fallback_interface -> index = -1;
1072 interface_stash (fallback_interface);
1073 return status == ISC_R_SUCCESS;
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
1085 if (fallback_interface)
1086 if_reinitialize_send (fallback_interface);
1087
1088 interfaces_invalidated = 1;
1089 }
1090
1091 isc_result_t got_one (h)
1092 omapi_object_t *h;
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;
1104 struct interface_info *ip;
1105
1106 if (h -> type != dhcp_type_interface)
1107 return DHCP_R_INVALIDARG;
1108 ip = (struct interface_info *)h;
1109
1110 again:
1111 if ((result =
1112 receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
1113 log_error ("receive_packet failed on %s: %m", ip -> name);
1114 return ISC_R_UNEXPECTED;
1115 }
1116 if (result == 0)
1117 return ISC_R_UNEXPECTED;
1118
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)
1129 return ISC_R_UNEXPECTED;
1130
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
1150 if (bootp_packet_handler) {
1151 ifrom.len = 4;
1152 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
1153
1154 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
1155 from.sin_port, ifrom, &hfrom);
1156 }
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;
1162 return ISC_R_SUCCESS;
1163 }
1164
1165 #ifdef DHCPv6
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;
1175 unsigned int if_idx = 0;
1176
1177 if (h->type != dhcp_type_interface) {
1178 return DHCP_R_INVALIDARG;
1179 }
1180 ip = (struct interface_info *)h;
1181
1182 result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf),
1183 &from, &to, &if_idx);
1184 if (result < 0) {
1185 log_error("receive_packet6() failed on %s: %m", ip->name);
1186 return ISC_R_UNEXPECTED;
1187 }
1188
1189 /* 0 is 'any' interface. */
1190 if (if_idx == 0)
1191 return ISC_R_NOTFOUND;
1192
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
1206 /* Seek forward to find the matching source interface. */
1207 ip = interfaces;
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
1214 (*dhcpv6_packet_handler)(ip, buf,
1215 result, from.sin6_port,
1216 &ifrom, is_unicast);
1217 }
1218
1219 return ISC_R_SUCCESS;
1220 }
1221 #endif /* DHCPv6 */
1222
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)
1227 {
1228 struct interface_info *interface;
1229 isc_result_t status;
1230
1231 if (h -> type != dhcp_type_interface)
1232 return DHCP_R_INVALIDARG;
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
1244 return DHCP_R_INVALIDARG;
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));
1252 if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
1253 return status;
1254 }
1255
1256 return ISC_R_NOTFOUND;
1257 }
1258
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)
1264 {
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;
1272
1273 if (h -> type != dhcp_type_interface)
1274 return DHCP_R_INVALIDARG;
1275 interface = (struct interface_info *)h;
1276
1277 if (interface -> ifp) {
1278 dfree (interface -> ifp, file, line);
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
1294 return ISC_R_SUCCESS;
1295 }
1296
1297 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
1298 const char *name, va_list ap)
1299 {
1300 struct interface_info *ip, *interface;
1301 isc_result_t status;
1302
1303 if (h -> type != dhcp_type_interface)
1304 return DHCP_R_INVALIDARG;
1305 interface = (struct interface_info *)h;
1306
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);
1315
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);
1321 }
1322
1323 /* Try to find some inner object that can take the value. */
1324 if (h -> inner && h -> inner -> type -> signal_handler) {
1325 status = ((*(h -> inner -> type -> signal_handler))
1326 (h -> inner, name, ap));
1327 if (status == ISC_R_SUCCESS)
1328 return status;
1329 }
1330 return ISC_R_NOTFOUND;
1331 }
1332
1333 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
1334 omapi_object_t *id,
1335 omapi_object_t *h)
1336 {
1337 struct interface_info *interface;
1338 isc_result_t status;
1339
1340 if (h -> type != dhcp_type_interface)
1341 return DHCP_R_INVALIDARG;
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;
1349 if ((interface->flags & INTERFACE_REQUESTED) != 0)
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
1364 return ISC_R_SUCCESS;
1365 }
1366
1367 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
1368 omapi_object_t *id,
1369 omapi_object_t *ref)
1370 {
1371 omapi_value_t *tv = (omapi_value_t *)0;
1372 isc_result_t status;
1373 struct interface_info *interface;
1374
1375 if (!ref)
1376 return DHCP_R_NOKEYS;
1377
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);
1390 return DHCP_R_INVALIDARG;
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) {
1397 char *s;
1398 unsigned len;
1399 for (interface = interfaces; interface;
1400 interface = interface -> next) {
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)))
1410 break;
1411 }
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
1429 omapi_value_dereference (&tv, MDL);
1430 if (*ip && *ip != (omapi_object_t *)interface) {
1431 omapi_object_dereference (ip, MDL);
1432 return DHCP_R_KEYCONFLICT;
1433 } else if (!interface) {
1434 if (*ip)
1435 omapi_object_dereference (ip, MDL);
1436 return ISC_R_NOTFOUND;
1437 } else if (!*ip)
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)
1446 return DHCP_R_NOKEYS;
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;
1456
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;
1465 }
1466
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
1513 switch(local_family) {
1514 #ifdef DHCPv6
1515 case AF_INET6:
1516 if_deregister6(interface);
1517 break;
1518 #endif /* DHCPv6 */
1519 case AF_INET:
1520 default:
1521 if_deregister_send(interface);
1522 if_deregister_receive(interface);
1523 break;
1524 }
1525
1526 return ISC_R_SUCCESS;
1527 }
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);
1546 if (!vec) {
1547 log_error ("interface_stash: allocation failed ");
1548 return;
1549 }
1550
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 }
1560
1561 interface_vector = vec;
1562 }
1563
1564 interface_reference (&interface_vector [tptr -> index], tptr, MDL);
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 }
1586