Remove building with NOCRYPTO option
[minix.git] / external / bsd / dhcp / dist / common / discover.c
blob6ee3c5909f3b01faca23c0c304a91c5a17ca1bf3
1 /* $NetBSD: discover.c,v 1.4 2014/07/12 12:09:37 spz Exp $ */
2 /* discover.c
4 Find and identify the network interfaces. */
6 /*
7 * Copyright (c) 2013-2014 by Internet Systems Consortium, Inc. ("ISC")
8 * Copyright (c) 2004-2009,2011 by Internet Systems Consortium, Inc. ("ISC")
9 * Copyright (c) 1995-2003 by Internet Software Consortium
11 * Permission to use, copy, modify, and distribute this software for any
12 * purpose with or without fee is hereby granted, provided that the above
13 * copyright notice and this permission notice appear in all copies.
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.
23 * Internet Systems Consortium, Inc.
24 * 950 Charter Street
25 * Redwood City, CA 94063
26 * <info@isc.org>
27 * https://www.isc.org/
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: discover.c,v 1.4 2014/07/12 12:09:37 spz Exp $");
34 #include "dhcpd.h"
36 #define BSD_COMP /* needed on Solaris for SIOCGLIFNUM */
37 #include <sys/ioctl.h>
38 #include <errno.h>
40 #ifdef HAVE_NET_IF6_H
41 # include <net/if6.h>
42 #endif
44 struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
45 int interfaces_invalidated;
46 int quiet_interface_discovery;
47 u_int16_t local_port;
48 u_int16_t remote_port;
49 int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
50 int (*dhcp_interface_discovery_hook) (struct interface_info *);
51 isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
52 int (*dhcp_interface_shutdown_hook) (struct interface_info *);
54 struct in_addr limited_broadcast;
56 int local_family = AF_INET;
57 struct in_addr local_address;
59 void (*bootp_packet_handler) (struct interface_info *,
60 struct dhcp_packet *, unsigned,
61 unsigned int,
62 struct iaddr, struct hardware *);
64 #ifdef DHCPv6
65 void (*dhcpv6_packet_handler)(struct interface_info *,
66 const char *, int,
67 int, const struct iaddr *,
68 isc_boolean_t);
69 #endif /* DHCPv6 */
72 omapi_object_type_t *dhcp_type_interface;
73 #if defined (TRACING)
74 trace_type_t *interface_trace;
75 trace_type_t *inpacket_trace;
76 trace_type_t *outpacket_trace;
77 #endif
78 struct interface_info **interface_vector;
79 int interface_count;
80 int interface_max;
82 OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
84 isc_result_t interface_setup ()
86 isc_result_t status;
87 status = omapi_object_type_register (&dhcp_type_interface,
88 "interface",
89 dhcp_interface_set_value,
90 dhcp_interface_get_value,
91 dhcp_interface_destroy,
92 dhcp_interface_signal_handler,
93 dhcp_interface_stuff_values,
94 dhcp_interface_lookup,
95 dhcp_interface_create,
96 dhcp_interface_remove,
97 0, 0, 0,
98 sizeof (struct interface_info),
99 interface_initialize, RC_MISC);
100 if (status != ISC_R_SUCCESS)
101 log_fatal ("Can't register interface object type: %s",
102 isc_result_totext (status));
104 return status;
107 #if defined (TRACING)
108 void interface_trace_setup ()
110 interface_trace = trace_type_register ("interface", (void *)0,
111 trace_interface_input,
112 trace_interface_stop, MDL);
113 inpacket_trace = trace_type_register ("inpacket", (void *)0,
114 trace_inpacket_input,
115 trace_inpacket_stop, MDL);
116 outpacket_trace = trace_type_register ("outpacket", (void *)0,
117 trace_outpacket_input,
118 trace_outpacket_stop, MDL);
120 #endif
122 isc_result_t interface_initialize (omapi_object_t *ipo,
123 const char *file, int line)
125 struct interface_info *ip = (struct interface_info *)ipo;
126 ip -> rfdesc = ip -> wfdesc = -1;
127 return ISC_R_SUCCESS;
132 * Scanning for Interfaces
133 * -----------------------
135 * To find interfaces, we create an iterator that abstracts out most
136 * of the platform specifics. Use is fairly straightforward:
138 * - begin_iface_scan() starts the process.
139 * - Use next_iface() until it returns 0.
140 * - end_iface_scan() performs any necessary cleanup.
142 * We check for errors on each call to next_iface(), which returns a
143 * description of the error as a string if any occurs.
145 * We currently have code for Solaris and Linux. Other systems need
146 * to have code written.
148 * NOTE: the long-term goal is to use the interface code from BIND 9.
151 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && defined(SIOCGLIFFLAGS)
153 /* HP/UX doesn't define struct lifconf, instead they define struct
154 * if_laddrconf. Similarly, 'struct lifreq' and 'struct lifaddrreq'.
156 #ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
157 # define lifc_len iflc_len
158 # define lifc_buf iflc_buf
159 # define lifc_req iflc_req
160 # define LIFCONF if_laddrconf
161 #else
162 # define ISC_HAVE_LIFC_FAMILY 1
163 # define ISC_HAVE_LIFC_FLAGS 1
164 # define LIFCONF lifconf
165 #endif
167 #ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
168 # define lifr_addr iflr_addr
169 # define lifr_name iflr_name
170 # define lifr_dstaddr iflr_dstaddr
171 # define lifr_flags iflr_flags
172 # define sockaddr_storage sockaddr_ext
173 # define ss_family sa_family
174 # define LIFREQ if_laddrreq
175 #else
176 # define LIFREQ lifreq
177 #endif
179 #ifndef IF_NAMESIZE
180 # if defined(LIFNAMSIZ)
181 # define IF_NAMESIZE LIFNAMSIZ
182 # elif defined(IFNAMSIZ)
183 # define IF_NAMESIZE IFNAMSIZ
184 # else
185 # define IF_NAMESIZE 16
186 # endif
187 #endif
188 #elif !defined(__linux) && !defined(HAVE_IFADDRS_H)
189 # define SIOCGLIFCONF SIOCGIFCONF
190 # define SIOCGLIFFLAGS SIOCGIFFLAGS
191 # define LIFREQ ifreq
192 # define LIFCONF ifconf
193 # define lifr_name ifr_name
194 # define lifr_addr ifr_addr
195 # define lifr_flags ifr_flags
196 # define lifc_len ifc_len
197 # define lifc_buf ifc_buf
198 # define lifc_req ifc_req
199 #ifdef _AIX
200 # define ss_family __ss_family
201 #endif
202 #endif
204 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
206 * Solaris support
207 * ---------------
209 * The SIOCGLIFCONF ioctl() are the extension that you need to use
210 * on Solaris to get information about IPv6 addresses.
212 * Solaris' extended interface is documented in the if_tcp man page.
216 * Structure holding state about the scan.
218 struct iface_conf_list {
219 int sock; /* file descriptor used to get information */
220 int num; /* total number of interfaces */
221 struct LIFCONF conf; /* structure used to get information */
222 int next; /* next interface to retrieve when iterating */
226 * Structure used to return information about a specific interface.
228 struct iface_info {
229 char name[IF_NAMESIZE+1]; /* name of the interface, e.g. "bge0" */
230 struct sockaddr_storage addr; /* address information */
231 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
235 * Start a scan of interfaces.
237 * The iface_conf_list structure maintains state for this process.
239 static int
240 begin_iface_scan(struct iface_conf_list *ifaces) {
241 #ifdef ISC_PLATFORM_HAVELIFNUM
242 struct lifnum lifnum;
243 #else
244 int lifnum;
245 #endif
247 ifaces->sock = socket(local_family, SOCK_DGRAM, IPPROTO_UDP);
248 if (ifaces->sock < 0) {
249 log_error("Error creating socket to list interfaces; %m");
250 return 0;
253 memset(&lifnum, 0, sizeof(lifnum));
254 #ifdef ISC_PLATFORM_HAVELIFNUM
255 lifnum.lifn_family = AF_UNSPEC;
256 #endif
257 #ifdef SIOCGLIFNUM
258 if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) {
259 log_error("Error finding total number of interfaces; %m");
260 close(ifaces->sock);
261 ifaces->sock = -1;
262 return 0;
265 #ifdef ISC_PLATFORM_HAVELIFNUM
266 ifaces->num = lifnum.lifn_count;
267 #else
268 ifaces->num = lifnum;
269 #endif
270 #else
271 ifaces->num = 64;
272 #endif /* SIOCGLIFNUM */
274 memset(&ifaces->conf, 0, sizeof(ifaces->conf));
275 #ifdef ISC_HAVE_LIFC_FAMILY
276 ifaces->conf.lifc_family = AF_UNSPEC;
277 #endif
278 ifaces->conf.lifc_len = ifaces->num * sizeof(struct LIFREQ);
279 ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL);
280 if (ifaces->conf.lifc_buf == NULL) {
281 log_fatal("Out of memory getting interface list.");
284 if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) {
285 log_error("Error getting interfaces configuration list; %m");
286 dfree(ifaces->conf.lifc_buf, MDL);
287 close(ifaces->sock);
288 ifaces->sock = -1;
289 return 0;
292 ifaces->next = 0;
294 return 1;
298 * Retrieve the next interface.
300 * Returns information in the info structure.
301 * Sets err to 1 if there is an error, otherwise 0.
303 static int
304 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
305 struct LIFREQ *p;
306 struct LIFREQ tmp;
307 isc_boolean_t foundif;
308 #if defined(sun) || defined(__linux)
309 /* Pointer used to remove interface aliases. */
310 char *s;
311 #endif
313 do {
314 foundif = ISC_FALSE;
316 if (ifaces->next >= ifaces->num) {
317 *err = 0;
318 return 0;
321 p = ifaces->conf.lifc_req;
322 p += ifaces->next;
324 if (strlen(p->lifr_name) >= sizeof(info->name)) {
325 *err = 1;
326 log_error("Interface name '%s' too long", p->lifr_name);
327 return 0;
330 /* Reject if interface address family does not match */
331 if (p->lifr_addr.ss_family != local_family) {
332 ifaces->next++;
333 continue;
336 strcpy(info->name, p->lifr_name);
337 memset(&info->addr, 0, sizeof(info->addr));
338 memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr));
340 #if defined(sun) || defined(__linux)
341 /* interface aliases look like "eth0:1" or "wlan1:3" */
342 s = strchr(info->name, ':');
343 if (s != NULL) {
344 *s = '\0';
346 #endif /* defined(sun) || defined(__linux) */
348 foundif = ISC_TRUE;
349 } while ((foundif == ISC_FALSE) ||
350 (strncmp(info->name, "dummy", 5) == 0));
352 memset(&tmp, 0, sizeof(tmp));
353 strcpy(tmp.lifr_name, info->name);
354 if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) {
355 log_error("Error getting interface flags for '%s'; %m",
356 p->lifr_name);
357 *err = 1;
358 return 0;
360 info->flags = tmp.lifr_flags;
362 ifaces->next++;
363 *err = 0;
364 return 1;
368 * End scan of interfaces.
370 static void
371 end_iface_scan(struct iface_conf_list *ifaces) {
372 dfree(ifaces->conf.lifc_buf, MDL);
373 close(ifaces->sock);
374 ifaces->sock = -1;
377 #elif __linux /* !HAVE_SIOCGLIFCONF */
379 * Linux support
380 * -------------
382 * In Linux, we use the /proc pseudo-filesystem to get information
383 * about interfaces, along with selected ioctl() calls.
385 * Linux low level access is documented in the netdevice man page.
389 * Structure holding state about the scan.
391 struct iface_conf_list {
392 int sock; /* file descriptor used to get information */
393 FILE *fp; /* input from /proc/net/dev */
394 #ifdef DHCPv6
395 FILE *fp6; /* input from /proc/net/if_inet6 */
396 #endif
400 * Structure used to return information about a specific interface.
402 struct iface_info {
403 char name[IFNAMSIZ]; /* name of the interface, e.g. "eth0" */
404 struct sockaddr_storage addr; /* address information */
405 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
409 * Start a scan of interfaces.
411 * The iface_conf_list structure maintains state for this process.
413 static int
414 begin_iface_scan(struct iface_conf_list *ifaces) {
415 char buf[256];
416 int len;
417 int i;
419 ifaces->fp = fopen("/proc/net/dev", "r");
420 if (ifaces->fp == NULL) {
421 log_error("Error opening '/proc/net/dev' to list interfaces");
422 return 0;
426 * The first 2 lines are header information, so read and ignore them.
428 for (i=0; i<2; i++) {
429 if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
430 log_error("Error reading headers from '/proc/net/dev'");
431 fclose(ifaces->fp);
432 ifaces->fp = NULL;
433 return 0;
435 len = strlen(buf);
436 if ((len <= 0) || (buf[len-1] != '\n')) {
437 log_error("Bad header line in '/proc/net/dev'");
438 fclose(ifaces->fp);
439 ifaces->fp = NULL;
440 return 0;
444 ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
445 if (ifaces->sock < 0) {
446 log_error("Error creating socket to list interfaces; %m");
447 fclose(ifaces->fp);
448 ifaces->fp = NULL;
449 return 0;
452 #ifdef DHCPv6
453 if (local_family == AF_INET6) {
454 ifaces->fp6 = fopen("/proc/net/if_inet6", "r");
455 if (ifaces->fp6 == NULL) {
456 log_error("Error opening '/proc/net/if_inet6' to "
457 "list IPv6 interfaces; %m");
458 close(ifaces->sock);
459 ifaces->sock = -1;
460 fclose(ifaces->fp);
461 ifaces->fp = NULL;
462 return 0;
465 #endif
467 return 1;
471 * Read our IPv4 interfaces from /proc/net/dev.
473 * The file looks something like this:
475 * Inter-| Receive ...
476 * face |bytes packets errs drop fifo frame ...
477 * lo: 1580562 4207 0 0 0 0 ...
478 * eth0: 0 0 0 0 0 0 ...
479 * eth1:1801552440 37895 0 14 0 ...
481 * We only care about the interface name, which is at the start of
482 * each line.
484 * We use an ioctl() to get the address and flags for each interface.
486 static int
487 next_iface4(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
488 char buf[256];
489 int len;
490 char *p;
491 char *name;
492 struct ifreq tmp;
495 * Loop exits when we find an interface that has an address, or
496 * when we run out of interfaces.
498 for (;;) {
499 do {
501 * Read the next line in the file.
503 if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
504 if (ferror(ifaces->fp)) {
505 *err = 1;
506 log_error("Error reading interface "
507 "information");
508 } else {
509 *err = 0;
511 return 0;
515 * Make sure the line is a nice,
516 * newline-terminated line.
518 len = strlen(buf);
519 if ((len <= 0) || (buf[len-1] != '\n')) {
520 log_error("Bad line reading interface "
521 "information");
522 *err = 1;
523 return 0;
527 * Figure out our name.
529 p = strrchr(buf, ':');
530 if (p == NULL) {
531 log_error("Bad line reading interface "
532 "information (no colon)");
533 *err = 1;
534 return 0;
536 *p = '\0';
537 name = buf;
538 while (isspace(*name)) {
539 name++;
543 * Copy our name into our interface structure.
545 len = p - name;
546 if (len >= sizeof(info->name)) {
547 *err = 1;
548 log_error("Interface name '%s' too long", name);
549 return 0;
551 strcpy(info->name, name);
553 #ifdef ALIAS_NAMED_PERMUTED
554 /* interface aliases look like "eth0:1" or "wlan1:3" */
555 s = strchr(info->name, ':');
556 if (s != NULL) {
557 *s = '\0';
559 #endif
561 #ifdef SKIP_DUMMY_INTERFACES
562 } while (strncmp(info->name, "dummy", 5) == 0);
563 #else
564 } while (0);
565 #endif
567 memset(&tmp, 0, sizeof(tmp));
568 strcpy(tmp.ifr_name, name);
569 if (ioctl(ifaces->sock, SIOCGIFADDR, &tmp) < 0) {
570 if (errno == EADDRNOTAVAIL) {
571 continue;
573 log_error("Error getting interface address "
574 "for '%s'; %m", name);
575 *err = 1;
576 return 0;
578 memcpy(&info->addr, &tmp.ifr_addr, sizeof(tmp.ifr_addr));
580 memset(&tmp, 0, sizeof(tmp));
581 strcpy(tmp.ifr_name, name);
582 if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
583 log_error("Error getting interface flags for '%s'; %m",
584 name);
585 *err = 1;
586 return 0;
588 info->flags = tmp.ifr_flags;
590 *err = 0;
591 return 1;
595 #ifdef DHCPv6
597 * Read our IPv6 interfaces from /proc/net/if_inet6.
599 * The file looks something like this:
601 * fe80000000000000025056fffec00008 05 40 20 80 vmnet8
602 * 00000000000000000000000000000001 01 80 10 80 lo
603 * fe80000000000000025056fffec00001 06 40 20 80 vmnet1
604 * 200108881936000202166ffffe497d9b 03 40 00 00 eth1
605 * fe8000000000000002166ffffe497d9b 03 40 20 80 eth1
607 * We get IPv6 address from the start, the interface name from the end,
608 * and ioctl() to get flags.
610 static int
611 next_iface6(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
612 char buf[256];
613 int len;
614 char *p;
615 char *name;
616 int i;
617 struct sockaddr_in6 addr;
618 struct ifreq tmp;
620 do {
622 * Read the next line in the file.
624 if (fgets(buf, sizeof(buf), ifaces->fp6) == NULL) {
625 if (ferror(ifaces->fp6)) {
626 *err = 1;
627 log_error("Error reading IPv6 "
628 "interface information");
629 } else {
630 *err = 0;
632 return 0;
636 * Make sure the line is a nice, newline-terminated line.
638 len = strlen(buf);
639 if ((len <= 0) || (buf[len-1] != '\n')) {
640 log_error("Bad line reading IPv6 "
641 "interface information");
642 *err = 1;
643 return 0;
647 * Figure out our name.
649 buf[--len] = '\0';
650 p = strrchr(buf, ' ');
651 if (p == NULL) {
652 log_error("Bad line reading IPv6 interface "
653 "information (no space)");
654 *err = 1;
655 return 0;
657 name = p+1;
660 * Copy our name into our interface structure.
662 len = strlen(name);
663 if (len >= sizeof(info->name)) {
664 *err = 1;
665 log_error("IPv6 interface name '%s' too long", name);
666 return 0;
668 strcpy(info->name, name);
670 #ifdef SKIP_DUMMY_INTERFACES
671 } while (strncmp(info->name, "dummy", 5) == 0);
672 #else
673 } while (0);
674 #endif
677 * Double-check we start with the IPv6 address.
679 for (i=0; i<32; i++) {
680 if (!isxdigit(buf[i]) || isupper(buf[i])) {
681 *err = 1;
682 log_error("Bad line reading IPv6 interface address "
683 "for '%s'", name);
684 return 0;
689 * Load our socket structure.
691 memset(&addr, 0, sizeof(addr));
692 addr.sin6_family = AF_INET6;
693 for (i=0; i<16; i++) {
694 unsigned char byte;
695 static const char hex[] = "0123456789abcdef";
696 byte = ((index(hex, buf[i * 2]) - hex) << 4) |
697 (index(hex, buf[i * 2 + 1]) - hex);
698 addr.sin6_addr.s6_addr[i] = byte;
700 memcpy(&info->addr, &addr, sizeof(addr));
703 * Get our flags.
705 memset(&tmp, 0, sizeof(tmp));
706 strcpy(tmp.ifr_name, name);
707 if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
708 log_error("Error getting interface flags for '%s'; %m", name);
709 *err = 1;
710 return 0;
712 info->flags = tmp.ifr_flags;
714 *err = 0;
715 return 1;
717 #endif /* DHCPv6 */
720 * Retrieve the next interface.
722 * Returns information in the info structure.
723 * Sets err to 1 if there is an error, otherwise 0.
725 static int
726 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
727 if (next_iface4(info, err, ifaces)) {
728 return 1;
730 #ifdef DHCPv6
731 if (!(*err)) {
732 if (local_family == AF_INET6)
733 return next_iface6(info, err, ifaces);
735 #endif
736 return 0;
740 * End scan of interfaces.
742 static void
743 end_iface_scan(struct iface_conf_list *ifaces) {
744 fclose(ifaces->fp);
745 ifaces->fp = NULL;
746 close(ifaces->sock);
747 ifaces->sock = -1;
748 #ifdef DHCPv6
749 if (local_family == AF_INET6) {
750 fclose(ifaces->fp6);
751 ifaces->fp6 = NULL;
753 #endif
755 #else
758 * BSD support
759 * -----------
761 * FreeBSD, NetBSD, OpenBSD, and OS X all have the getifaddrs()
762 * function.
764 * The getifaddrs() man page describes the use.
767 #include <ifaddrs.h>
770 * Structure holding state about the scan.
772 struct iface_conf_list {
773 struct ifaddrs *head; /* beginning of the list */
774 struct ifaddrs *next; /* current position in the list */
778 * Structure used to return information about a specific interface.
780 struct iface_info {
781 char name[IFNAMSIZ]; /* name of the interface, e.g. "bge0" */
782 struct sockaddr_storage addr; /* address information */
783 isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
787 * Start a scan of interfaces.
789 * The iface_conf_list structure maintains state for this process.
791 static int
792 begin_iface_scan(struct iface_conf_list *ifaces) {
793 if (getifaddrs(&ifaces->head) != 0) {
794 log_error("Error getting interfaces; %m");
795 return 0;
797 ifaces->next = ifaces->head;
798 return 1;
802 * Retrieve the next interface.
804 * Returns information in the info structure.
805 * Sets err to 1 if there is an error, otherwise 0.
807 static int
808 next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
809 if (ifaces->next == NULL) {
810 *err = 0;
811 return 0;
813 if (strlen(ifaces->next->ifa_name) >= sizeof(info->name)) {
814 log_error("Interface name '%s' too long",
815 ifaces->next->ifa_name);
816 *err = 1;
817 return 0;
819 strcpy(info->name, ifaces->next->ifa_name);
820 memcpy(&info->addr, ifaces->next->ifa_addr,
821 ifaces->next->ifa_addr->sa_len);
822 info->flags = ifaces->next->ifa_flags;
823 ifaces->next = ifaces->next->ifa_next;
824 *err = 0;
825 return 1;
829 * End scan of interfaces.
831 static void
832 end_iface_scan(struct iface_conf_list *ifaces) {
833 freeifaddrs(ifaces->head);
834 ifaces->head = NULL;
835 ifaces->next = NULL;
837 #endif
839 /* XXX: perhaps create drealloc() rather than do it manually */
840 static void
841 add_ipv4_addr_to_interface(struct interface_info *iface,
842 const struct in_addr *addr) {
844 * We don't expect a lot of addresses per IPv4 interface, so
845 * we use 4, as our "chunk size" for collecting addresses.
847 if (iface->addresses == NULL) {
848 iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL);
849 if (iface->addresses == NULL) {
850 log_fatal("Out of memory saving IPv4 address "
851 "on interface.");
853 iface->address_count = 0;
854 iface->address_max = 4;
855 } else if (iface->address_count >= iface->address_max) {
856 struct in_addr *tmp;
857 int new_max;
859 new_max = iface->address_max + 4;
860 tmp = dmalloc(new_max * sizeof(struct in_addr), MDL);
861 if (tmp == NULL) {
862 log_fatal("Out of memory saving IPv4 address "
863 "on interface.");
865 memcpy(tmp,
866 iface->addresses,
867 iface->address_max * sizeof(struct in_addr));
868 dfree(iface->addresses, MDL);
869 iface->addresses = tmp;
870 iface->address_max = new_max;
872 iface->addresses[iface->address_count++] = *addr;
875 #ifdef DHCPv6
876 /* XXX: perhaps create drealloc() rather than do it manually */
877 static void
878 add_ipv6_addr_to_interface(struct interface_info *iface,
879 const struct in6_addr *addr) {
881 * Each IPv6 interface will have at least two IPv6 addresses,
882 * and likely quite a few more. So we use 8, as our "chunk size" for
883 * collecting addresses.
885 if (iface->v6addresses == NULL) {
886 iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL);
887 if (iface->v6addresses == NULL) {
888 log_fatal("Out of memory saving IPv6 address "
889 "on interface.");
891 iface->v6address_count = 0;
892 iface->v6address_max = 8;
893 } else if (iface->v6address_count >= iface->v6address_max) {
894 struct in6_addr *tmp;
895 int new_max;
897 new_max = iface->v6address_max + 8;
898 tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL);
899 if (tmp == NULL) {
900 log_fatal("Out of memory saving IPv6 address "
901 "on interface.");
903 memcpy(tmp,
904 iface->v6addresses,
905 iface->v6address_max * sizeof(struct in6_addr));
906 dfree(iface->v6addresses, MDL);
907 iface->v6addresses = tmp;
908 iface->v6address_max = new_max;
910 iface->v6addresses[iface->v6address_count++] = *addr;
912 #endif /* DHCPv6 */
914 /* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
915 For each interface that's of type INET and not the loopback interface,
916 register that interface with the network I/O software, figure out what
917 subnet it's on, and add it to the list of interfaces. */
919 void
920 discover_interfaces(int state) {
921 struct iface_conf_list ifaces;
922 struct iface_info info;
923 int err;
925 struct interface_info *tmp;
926 struct interface_info *last, *next;
928 #ifdef DHCPv6
929 char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
930 #endif /* DHCPv6 */
933 struct subnet *subnet;
934 int ir;
935 isc_result_t status;
936 int wifcount = 0;
938 static int setup_fallback = 0;
940 if (!begin_iface_scan(&ifaces)) {
941 log_fatal("Can't get list of interfaces.");
944 /* If we already have a list of interfaces, and we're running as
945 a DHCP server, the interfaces were requested. */
946 if (interfaces && (state == DISCOVER_SERVER ||
947 state == DISCOVER_RELAY ||
948 state == DISCOVER_REQUESTED))
949 ir = 0;
950 else if (state == DISCOVER_UNCONFIGURED)
951 ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
952 else
953 ir = INTERFACE_REQUESTED;
955 /* Cycle through the list of interfaces looking for IP addresses. */
956 while (next_iface(&info, &err, &ifaces)) {
958 /* See if we've seen an interface that matches this one. */
959 for (tmp = interfaces; tmp; tmp = tmp->next) {
960 if (!strcmp(tmp->name, info.name))
961 break;
964 /* Skip non broadcast interfaces (plus loopback and
965 point-to-point in case an OS incorrectly marks them
966 as broadcast). Also skip down interfaces unless we're
967 trying to get a list of configurable interfaces. */
968 if ((((local_family == AF_INET &&
969 !(info.flags & IFF_BROADCAST)) ||
970 #ifdef DHCPv6
971 (local_family == AF_INET6 &&
972 !(info.flags & IFF_MULTICAST)) ||
973 #endif
974 info.flags & IFF_LOOPBACK ||
975 info.flags & IFF_POINTOPOINT) && !tmp) ||
976 (!(info.flags & IFF_UP) &&
977 state != DISCOVER_UNCONFIGURED))
978 continue;
980 /* If there isn't already an interface by this name,
981 allocate one. */
982 if (tmp == NULL) {
983 status = interface_allocate(&tmp, MDL);
984 if (status != ISC_R_SUCCESS) {
985 log_fatal("Error allocating interface %s: %s",
986 info.name, isc_result_totext(status));
988 strcpy(tmp->name, info.name);
989 interface_snorf(tmp, ir);
990 interface_dereference(&tmp, MDL);
991 tmp = interfaces; /* XXX */
994 if (dhcp_interface_discovery_hook) {
995 (*dhcp_interface_discovery_hook)(tmp);
998 if ((info.addr.ss_family == AF_INET) &&
999 (local_family == AF_INET)) {
1000 struct sockaddr_in *a = (struct sockaddr_in*)&info.addr;
1001 struct iaddr addr;
1003 /* We don't want the loopback interface. */
1004 if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) &&
1005 ((tmp->flags & INTERFACE_AUTOMATIC) &&
1006 state == DISCOVER_SERVER))
1007 continue;
1009 /* If the only address we have is 0.0.0.0, we
1010 shouldn't consider the interface configured. */
1011 if (a->sin_addr.s_addr != htonl(INADDR_ANY))
1012 tmp->configured = 1;
1014 add_ipv4_addr_to_interface(tmp, &a->sin_addr);
1016 /* invoke the setup hook */
1017 addr.len = 4;
1018 memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len);
1019 if (dhcp_interface_setup_hook) {
1020 (*dhcp_interface_setup_hook)(tmp, &addr);
1023 #ifdef DHCPv6
1024 else if ((info.addr.ss_family == AF_INET6) &&
1025 (local_family == AF_INET6)) {
1026 struct sockaddr_in6 *a =
1027 (struct sockaddr_in6*)&info.addr;
1028 struct iaddr addr;
1030 /* We don't want the loopback interface. */
1031 if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) &&
1032 ((tmp->flags & INTERFACE_AUTOMATIC) &&
1033 state == DISCOVER_SERVER))
1034 continue;
1036 /* If the only address we have is 0.0.0.0, we
1037 shouldn't consider the interface configured. */
1038 if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
1039 tmp->configured = 1;
1041 add_ipv6_addr_to_interface(tmp, &a->sin6_addr);
1043 /* invoke the setup hook */
1044 addr.len = 16;
1045 memcpy(addr.iabuf, &a->sin6_addr, addr.len);
1046 if (dhcp_interface_setup_hook) {
1047 (*dhcp_interface_setup_hook)(tmp, &addr);
1050 #endif /* DHCPv6 */
1053 if (err) {
1054 log_fatal("Error getting interface information.");
1057 end_iface_scan(&ifaces);
1060 /* Mock-up an 'ifp' structure which is no longer used in the
1061 * new interface-sensing code, but is used in higher layers
1062 * (for example to sense fallback interfaces).
1064 for (tmp = interfaces ; tmp != NULL ; tmp = tmp->next) {
1065 if (tmp->ifp == NULL) {
1066 struct ifreq *tif;
1068 tif = (struct ifreq *)dmalloc(sizeof(struct ifreq),
1069 MDL);
1070 if (tif == NULL)
1071 log_fatal("no space for ifp mockup.");
1072 strcpy(tif->ifr_name, tmp->name);
1073 tmp->ifp = tif;
1078 /* If we're just trying to get a list of interfaces that we might
1079 be able to configure, we can quit now. */
1080 if (state == DISCOVER_UNCONFIGURED) {
1081 return;
1084 /* Weed out the interfaces that did not have IP addresses. */
1085 tmp = last = next = NULL;
1086 if (interfaces)
1087 interface_reference (&tmp, interfaces, MDL);
1088 while (tmp) {
1089 if (next)
1090 interface_dereference (&next, MDL);
1091 if (tmp -> next)
1092 interface_reference (&next, tmp -> next, MDL);
1093 /* skip interfaces that are running already */
1094 if (tmp -> flags & INTERFACE_RUNNING) {
1095 interface_dereference(&tmp, MDL);
1096 if(next)
1097 interface_reference(&tmp, next, MDL);
1098 continue;
1100 if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
1101 state == DISCOVER_REQUESTED)
1102 tmp -> flags &= ~(INTERFACE_AUTOMATIC |
1103 INTERFACE_REQUESTED);
1105 #ifdef DHCPv6
1106 if (!(tmp->flags & INTERFACE_REQUESTED)) {
1107 #else
1108 if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
1109 #endif /* DHCPv6 */
1110 if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
1111 log_fatal ("%s: not found", tmp -> name);
1112 if (!last) {
1113 if (interfaces)
1114 interface_dereference (&interfaces,
1115 MDL);
1116 if (next)
1117 interface_reference (&interfaces, next, MDL);
1118 } else {
1119 interface_dereference (&last -> next, MDL);
1120 if (next)
1121 interface_reference (&last -> next,
1122 next, MDL);
1124 if (tmp -> next)
1125 interface_dereference (&tmp -> next, MDL);
1127 /* Remember the interface in case we need to know
1128 about it later. */
1129 if (dummy_interfaces) {
1130 interface_reference (&tmp -> next,
1131 dummy_interfaces, MDL);
1132 interface_dereference (&dummy_interfaces, MDL);
1134 interface_reference (&dummy_interfaces, tmp, MDL);
1135 interface_dereference (&tmp, MDL);
1136 if (next)
1137 interface_reference (&tmp, next, MDL);
1138 continue;
1140 last = tmp;
1142 /* We must have a subnet declaration for each interface. */
1143 if (!tmp->shared_network && (state == DISCOVER_SERVER)) {
1144 log_error("%s", "");
1145 if (local_family == AF_INET) {
1146 log_error("No subnet declaration for %s (%s).",
1147 tmp->name,
1148 (tmp->addresses == NULL) ?
1149 "no IPv4 addresses" :
1150 inet_ntoa(tmp->addresses[0]));
1151 #ifdef DHCPv6
1152 } else {
1153 if (tmp->v6addresses != NULL) {
1154 inet_ntop(AF_INET6,
1155 &tmp->v6addresses[0],
1156 abuf,
1157 sizeof(abuf));
1158 } else {
1159 strcpy(abuf, "no IPv6 addresses");
1161 log_error("No subnet6 declaration for %s (%s).",
1162 tmp->name,
1163 abuf);
1164 #endif /* DHCPv6 */
1166 if (supports_multiple_interfaces(tmp)) {
1167 log_error ("** Ignoring requests on %s. %s",
1168 tmp -> name, "If this is not what");
1169 log_error (" you want, please write %s",
1170 #ifdef DHCPv6
1171 (local_family != AF_INET) ?
1172 "a subnet6 declaration" :
1173 #endif
1174 "a subnet declaration");
1175 log_error (" in your dhcpd.conf file %s",
1176 "for the network segment");
1177 log_error (" to %s %s %s",
1178 "which interface",
1179 tmp -> name, "is attached. **");
1180 log_error ("%s", "");
1181 goto next;
1182 } else {
1183 log_error ("You must write a %s",
1184 #ifdef DHCPv6
1185 (local_family != AF_INET) ?
1186 "subnet6 declaration for this" :
1187 #endif
1188 "subnet declaration for this");
1189 log_error ("subnet. You cannot prevent %s",
1190 "the DHCP server");
1191 log_error ("from listening on this subnet %s",
1192 "because your");
1193 log_fatal ("operating system does not %s.",
1194 "support this capability");
1198 /* Find subnets that don't have valid interface
1199 addresses... */
1200 for (subnet = (tmp -> shared_network
1201 ? tmp -> shared_network -> subnets
1202 : (struct subnet *)0);
1203 subnet; subnet = subnet -> next_sibling) {
1204 /* Set the interface address for this subnet
1205 to the first address we found. */
1206 if (subnet->interface_address.len == 0) {
1207 if (tmp->address_count > 0) {
1208 subnet->interface_address.len = 4;
1209 memcpy(subnet->interface_address.iabuf,
1210 &tmp->addresses[0].s_addr, 4);
1211 } else if (tmp->v6address_count > 0) {
1212 subnet->interface_address.len = 16;
1213 memcpy(subnet->interface_address.iabuf,
1214 &tmp->v6addresses[0].s6_addr,
1215 16);
1216 } else {
1217 /* XXX: should be one */
1218 log_error("%s missing an interface "
1219 "address", tmp->name);
1220 continue;
1225 /* Flag the index as not having been set, so that the
1226 interface registerer can set it or not as it chooses. */
1227 tmp -> index = -1;
1229 /* Register the interface... */
1230 if (local_family == AF_INET) {
1231 if_register_receive(tmp);
1232 if_register_send(tmp);
1233 #ifdef DHCPv6
1234 } else {
1235 if ((state == DISCOVER_SERVER) ||
1236 (state == DISCOVER_RELAY)) {
1237 if_register6(tmp, 1);
1238 } else {
1239 if_register_linklocal6(tmp);
1241 #endif /* DHCPv6 */
1244 interface_stash (tmp);
1245 wifcount++;
1246 #if defined (F_SETFD)
1247 if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0)
1248 log_error ("Can't set close-on-exec on %s: %m",
1249 tmp -> name);
1250 if (tmp -> rfdesc != tmp -> wfdesc) {
1251 if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0)
1252 log_error ("Can't set close-on-exec on %s: %m",
1253 tmp -> name);
1255 #endif
1256 next:
1257 interface_dereference (&tmp, MDL);
1258 if (next)
1259 interface_reference (&tmp, next, MDL);
1263 * Now register all the remaining interfaces as protocols.
1264 * We register with omapi to allow for control of the interface,
1265 * we've already registered the fd or socket with the socket
1266 * manager as part of if_register_receive().
1268 for (tmp = interfaces; tmp; tmp = tmp -> next) {
1269 /* not if it's been registered before */
1270 if (tmp -> flags & INTERFACE_RUNNING)
1271 continue;
1272 if (tmp -> rfdesc == -1)
1273 continue;
1274 switch (local_family) {
1275 #ifdef DHCPv6
1276 case AF_INET6:
1277 status = omapi_register_io_object((omapi_object_t *)tmp,
1278 if_readsocket,
1279 0, got_one_v6, 0, 0);
1280 break;
1281 #endif /* DHCPv6 */
1282 case AF_INET:
1283 default:
1284 status = omapi_register_io_object((omapi_object_t *)tmp,
1285 if_readsocket,
1286 0, got_one, 0, 0);
1287 break;
1290 if (status != ISC_R_SUCCESS)
1291 log_fatal ("Can't register I/O handle for %s: %s",
1292 tmp -> name, isc_result_totext (status));
1294 #if defined(DHCPv6)
1295 /* Only register the first interface for V6, since
1296 * servers and relays all use the same socket.
1297 * XXX: This has some messy side effects if we start
1298 * dynamically adding and removing interfaces, but
1299 * we're well beyond that point in terms of mess.
1301 if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY)) &&
1302 (local_family == AF_INET6))
1303 break;
1304 #endif
1305 } /* for (tmp = interfaces; ... */
1307 if (state == DISCOVER_SERVER && wifcount == 0) {
1308 log_info ("%s", "");
1309 log_fatal ("Not configured to listen on any interfaces!");
1312 if ((local_family == AF_INET) && !setup_fallback) {
1313 setup_fallback = 1;
1314 maybe_setup_fallback();
1317 #if defined (F_SETFD)
1318 if (fallback_interface) {
1319 if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
1320 log_error ("Can't set close-on-exec on fallback: %m");
1321 if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
1322 if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
1323 log_error ("Can't set close-on-exec on fallback: %m");
1326 #endif /* F_SETFD */
1329 int if_readsocket (h)
1330 omapi_object_t *h;
1332 struct interface_info *ip;
1334 if (h -> type != dhcp_type_interface)
1335 return -1;
1336 ip = (struct interface_info *)h;
1337 return ip -> rfdesc;
1340 int setup_fallback (struct interface_info **fp, const char *file, int line)
1342 isc_result_t status;
1344 status = interface_allocate (&fallback_interface, file, line);
1345 if (status != ISC_R_SUCCESS)
1346 log_fatal ("Error allocating fallback interface: %s",
1347 isc_result_totext (status));
1348 strcpy (fallback_interface -> name, "fallback");
1349 if (dhcp_interface_setup_hook)
1350 (*dhcp_interface_setup_hook) (fallback_interface,
1351 (struct iaddr *)0);
1352 status = interface_reference (fp, fallback_interface, file, line);
1354 fallback_interface -> index = -1;
1355 interface_stash (fallback_interface);
1356 return status == ISC_R_SUCCESS;
1359 void reinitialize_interfaces ()
1361 struct interface_info *ip;
1363 for (ip = interfaces; ip; ip = ip -> next) {
1364 if_reinitialize_receive (ip);
1365 if_reinitialize_send (ip);
1368 if (fallback_interface)
1369 if_reinitialize_send (fallback_interface);
1371 interfaces_invalidated = 1;
1374 isc_result_t got_one (h)
1375 omapi_object_t *h;
1377 struct sockaddr_in from;
1378 struct hardware hfrom;
1379 struct iaddr ifrom;
1380 int result;
1381 union {
1382 unsigned char packbuf [4095]; /* Packet input buffer.
1383 Must be as large as largest
1384 possible MTU. */
1385 struct dhcp_packet packet;
1386 } u;
1387 struct interface_info *ip;
1389 if (h -> type != dhcp_type_interface)
1390 return DHCP_R_INVALIDARG;
1391 ip = (struct interface_info *)h;
1393 again:
1394 if ((result =
1395 receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
1396 log_error ("receive_packet failed on %s: %m", ip -> name);
1397 return ISC_R_UNEXPECTED;
1399 if (result == 0)
1400 return ISC_R_UNEXPECTED;
1403 * If we didn't at least get the fixed portion of the BOOTP
1404 * packet, drop the packet.
1405 * Previously we allowed packets with no sname or filename
1406 * as we were aware of at least one client that did. But
1407 * a bug caused short packets to not work and nobody has
1408 * complained, it seems rational to tighten up that
1409 * restriction.
1411 if (result < DHCP_FIXED_NON_UDP)
1412 return ISC_R_UNEXPECTED;
1414 #if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
1416 /* We retrieve the ifindex from the unused hfrom variable */
1417 unsigned int ifindex;
1419 memcpy(&ifindex, hfrom.hbuf, sizeof (ifindex));
1422 * Seek forward from the first interface to find the matching
1423 * source interface by interface index.
1425 ip = interfaces;
1426 while ((ip != NULL) && (if_nametoindex(ip->name) != ifindex))
1427 ip = ip->next;
1428 if (ip == NULL)
1429 return ISC_R_NOTFOUND;
1431 #endif
1433 if (bootp_packet_handler) {
1434 ifrom.len = 4;
1435 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
1437 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
1438 from.sin_port, ifrom, &hfrom);
1441 /* If there is buffered data, read again. This is for, e.g.,
1442 bpf, which may return two packets at once. */
1443 if (ip -> rbuf_offset != ip -> rbuf_len)
1444 goto again;
1445 return ISC_R_SUCCESS;
1448 #ifdef DHCPv6
1449 isc_result_t
1450 got_one_v6(omapi_object_t *h) {
1451 struct sockaddr_in6 from;
1452 struct in6_addr to;
1453 struct iaddr ifrom;
1454 int result;
1455 char buf[65536]; /* maximum size for a UDP packet is 65536 */
1456 struct interface_info *ip;
1457 int is_unicast;
1458 unsigned int if_idx = 0;
1460 if (h->type != dhcp_type_interface) {
1461 return DHCP_R_INVALIDARG;
1463 ip = (struct interface_info *)h;
1465 result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf),
1466 &from, &to, &if_idx);
1467 if (result < 0) {
1468 log_error("receive_packet6() failed on %s: %m", ip->name);
1469 return ISC_R_UNEXPECTED;
1472 /* 0 is 'any' interface. */
1473 if (if_idx == 0)
1474 return ISC_R_NOTFOUND;
1476 if (dhcpv6_packet_handler != NULL) {
1478 * If a packet is not multicast, we assume it is unicast.
1480 if (IN6_IS_ADDR_MULTICAST(&to)) {
1481 is_unicast = ISC_FALSE;
1482 } else {
1483 is_unicast = ISC_TRUE;
1486 ifrom.len = 16;
1487 memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len);
1489 /* Seek forward to find the matching source interface. */
1490 ip = interfaces;
1491 while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx))
1492 ip = ip->next;
1494 if (ip == NULL)
1495 return ISC_R_NOTFOUND;
1497 (*dhcpv6_packet_handler)(ip, buf,
1498 result, from.sin6_port,
1499 &ifrom, is_unicast);
1502 return ISC_R_SUCCESS;
1504 #endif /* DHCPv6 */
1506 isc_result_t dhcp_interface_set_value (omapi_object_t *h,
1507 omapi_object_t *id,
1508 omapi_data_string_t *name,
1509 omapi_typed_data_t *value)
1511 struct interface_info *interface;
1512 isc_result_t status;
1514 if (h -> type != dhcp_type_interface)
1515 return DHCP_R_INVALIDARG;
1516 interface = (struct interface_info *)h;
1518 if (!omapi_ds_strcmp (name, "name")) {
1519 if ((value -> type == omapi_datatype_data ||
1520 value -> type == omapi_datatype_string) &&
1521 value -> u.buffer.len < sizeof interface -> name) {
1522 memcpy (interface -> name,
1523 value -> u.buffer.value,
1524 value -> u.buffer.len);
1525 interface -> name [value -> u.buffer.len] = 0;
1526 } else
1527 return DHCP_R_INVALIDARG;
1528 return ISC_R_SUCCESS;
1531 /* Try to find some inner object that can take the value. */
1532 if (h -> inner && h -> inner -> type -> set_value) {
1533 status = ((*(h -> inner -> type -> set_value))
1534 (h -> inner, id, name, value));
1535 if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
1536 return status;
1539 return ISC_R_NOTFOUND;
1543 isc_result_t dhcp_interface_get_value (omapi_object_t *h,
1544 omapi_object_t *id,
1545 omapi_data_string_t *name,
1546 omapi_value_t **value)
1548 return ISC_R_NOTIMPLEMENTED;
1551 isc_result_t dhcp_interface_destroy (omapi_object_t *h,
1552 const char *file, int line)
1554 struct interface_info *interface;
1556 if (h -> type != dhcp_type_interface)
1557 return DHCP_R_INVALIDARG;
1558 interface = (struct interface_info *)h;
1560 if (interface -> ifp) {
1561 dfree (interface -> ifp, file, line);
1562 interface -> ifp = 0;
1564 if (interface -> next)
1565 interface_dereference (&interface -> next, file, line);
1566 if (interface -> rbuf) {
1567 dfree (interface -> rbuf, file, line);
1568 interface -> rbuf = (unsigned char *)0;
1570 if (interface -> client)
1571 interface -> client = (struct client_state *)0;
1573 if (interface -> shared_network)
1574 omapi_object_dereference ((void *)
1575 &interface -> shared_network, MDL);
1577 return ISC_R_SUCCESS;
1580 isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
1581 const char *name, va_list ap)
1583 struct interface_info *ip, *interface;
1584 isc_result_t status;
1586 if (h -> type != dhcp_type_interface)
1587 return DHCP_R_INVALIDARG;
1588 interface = (struct interface_info *)h;
1590 /* If it's an update signal, see if the interface is dead right
1591 now, or isn't known at all, and if that's the case, revive it. */
1592 if (!strcmp (name, "update")) {
1593 for (ip = dummy_interfaces; ip; ip = ip -> next)
1594 if (ip == interface)
1595 break;
1596 if (ip && dhcp_interface_startup_hook)
1597 return (*dhcp_interface_startup_hook) (ip);
1599 for (ip = interfaces; ip; ip = ip -> next)
1600 if (ip == interface)
1601 break;
1602 if (!ip && dhcp_interface_startup_hook)
1603 return (*dhcp_interface_startup_hook) (ip);
1606 /* Try to find some inner object that can take the value. */
1607 if (h -> inner && h -> inner -> type -> signal_handler) {
1608 status = ((*(h -> inner -> type -> signal_handler))
1609 (h -> inner, name, ap));
1610 if (status == ISC_R_SUCCESS)
1611 return status;
1613 return ISC_R_NOTFOUND;
1616 isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
1617 omapi_object_t *id,
1618 omapi_object_t *h)
1620 struct interface_info *interface;
1621 isc_result_t status;
1623 if (h -> type != dhcp_type_interface)
1624 return DHCP_R_INVALIDARG;
1625 interface = (struct interface_info *)h;
1627 /* Write out all the values. */
1629 status = omapi_connection_put_name (c, "state");
1630 if (status != ISC_R_SUCCESS)
1631 return status;
1632 if ((interface->flags & INTERFACE_REQUESTED) != 0)
1633 status = omapi_connection_put_string (c, "up");
1634 else
1635 status = omapi_connection_put_string (c, "down");
1636 if (status != ISC_R_SUCCESS)
1637 return status;
1639 /* Write out the inner object, if any. */
1640 if (h -> inner && h -> inner -> type -> stuff_values) {
1641 status = ((*(h -> inner -> type -> stuff_values))
1642 (c, id, h -> inner));
1643 if (status == ISC_R_SUCCESS)
1644 return status;
1647 return ISC_R_SUCCESS;
1650 isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
1651 omapi_object_t *id,
1652 omapi_object_t *ref)
1654 omapi_value_t *tv = (omapi_value_t *)0;
1655 isc_result_t status;
1656 struct interface_info *interface;
1658 if (!ref)
1659 return DHCP_R_NOKEYS;
1661 /* First see if we were sent a handle. */
1662 status = omapi_get_value_str (ref, id, "handle", &tv);
1663 if (status == ISC_R_SUCCESS) {
1664 status = omapi_handle_td_lookup (ip, tv -> value);
1666 omapi_value_dereference (&tv, MDL);
1667 if (status != ISC_R_SUCCESS)
1668 return status;
1670 /* Don't return the object if the type is wrong. */
1671 if ((*ip) -> type != dhcp_type_interface) {
1672 omapi_object_dereference (ip, MDL);
1673 return DHCP_R_INVALIDARG;
1677 /* Now look for an interface name. */
1678 status = omapi_get_value_str (ref, id, "name", &tv);
1679 if (status == ISC_R_SUCCESS) {
1680 char *s;
1681 unsigned len;
1682 for (interface = interfaces; interface;
1683 interface = interface -> next) {
1684 s = memchr (interface -> name, 0, IFNAMSIZ);
1685 if (s)
1686 len = s - &interface -> name [0];
1687 else
1688 len = IFNAMSIZ;
1689 if ((tv -> value -> u.buffer.len == len &&
1690 !memcmp (interface -> name,
1691 (char *)tv -> value -> u.buffer.value,
1692 len)))
1693 break;
1695 if (!interface) {
1696 for (interface = dummy_interfaces;
1697 interface; interface = interface -> next) {
1698 s = memchr (interface -> name, 0, IFNAMSIZ);
1699 if (s)
1700 len = s - &interface -> name [0];
1701 else
1702 len = IFNAMSIZ;
1703 if ((tv -> value -> u.buffer.len == len &&
1704 !memcmp (interface -> name,
1705 (char *)
1706 tv -> value -> u.buffer.value,
1707 len)))
1708 break;
1712 omapi_value_dereference (&tv, MDL);
1713 if (*ip && *ip != (omapi_object_t *)interface) {
1714 omapi_object_dereference (ip, MDL);
1715 return DHCP_R_KEYCONFLICT;
1716 } else if (!interface) {
1717 if (*ip)
1718 omapi_object_dereference (ip, MDL);
1719 return ISC_R_NOTFOUND;
1720 } else if (!*ip)
1721 omapi_object_reference (ip,
1722 (omapi_object_t *)interface,
1723 MDL);
1726 /* If we get to here without finding an interface, no valid key was
1727 specified. */
1728 if (!*ip)
1729 return DHCP_R_NOKEYS;
1730 return ISC_R_SUCCESS;
1733 /* actually just go discover the interface */
1734 isc_result_t dhcp_interface_create (omapi_object_t **lp,
1735 omapi_object_t *id)
1737 struct interface_info *hp;
1738 isc_result_t status;
1740 hp = (struct interface_info *)0;
1741 status = interface_allocate (&hp, MDL);
1742 if (status != ISC_R_SUCCESS)
1743 return status;
1744 hp -> flags = INTERFACE_REQUESTED;
1745 status = interface_reference ((struct interface_info **)lp, hp, MDL);
1746 interface_dereference (&hp, MDL);
1747 return status;
1750 isc_result_t dhcp_interface_remove (omapi_object_t *lp,
1751 omapi_object_t *id)
1753 struct interface_info *interface, *ip, *last;
1755 interface = (struct interface_info *)lp;
1757 /* remove from interfaces */
1758 last = 0;
1759 for (ip = interfaces; ip; ip = ip -> next) {
1760 if (ip == interface) {
1761 if (last) {
1762 interface_dereference (&last -> next, MDL);
1763 if (ip -> next)
1764 interface_reference (&last -> next,
1765 ip -> next, MDL);
1766 } else {
1767 interface_dereference (&interfaces, MDL);
1768 if (ip -> next)
1769 interface_reference (&interfaces,
1770 ip -> next, MDL);
1772 if (ip -> next)
1773 interface_dereference (&ip -> next, MDL);
1774 break;
1776 last = ip;
1778 if (!ip)
1779 return ISC_R_NOTFOUND;
1781 /* add the interface to the dummy_interface list */
1782 if (dummy_interfaces) {
1783 interface_reference (&interface -> next,
1784 dummy_interfaces, MDL);
1785 interface_dereference (&dummy_interfaces, MDL);
1787 interface_reference (&dummy_interfaces, interface, MDL);
1789 /* do a DHCPRELEASE */
1790 if (dhcp_interface_shutdown_hook)
1791 (*dhcp_interface_shutdown_hook) (interface);
1793 /* remove the io object */
1794 omapi_unregister_io_object ((omapi_object_t *)interface);
1796 switch(local_family) {
1797 #ifdef DHCPv6
1798 case AF_INET6:
1799 if_deregister6(interface);
1800 break;
1801 #endif /* DHCPv6 */
1802 case AF_INET:
1803 default:
1804 if_deregister_send(interface);
1805 if_deregister_receive(interface);
1806 break;
1809 return ISC_R_SUCCESS;
1812 void interface_stash (struct interface_info *tptr)
1814 struct interface_info **vec;
1815 int delta;
1817 /* If the registerer didn't assign an index, assign one now. */
1818 if (tptr -> index == -1) {
1819 tptr -> index = interface_count++;
1820 while (tptr -> index < interface_max &&
1821 interface_vector [tptr -> index])
1822 tptr -> index = interface_count++;
1825 if (interface_max <= tptr -> index) {
1826 delta = tptr -> index - interface_max + 10;
1827 vec = dmalloc ((interface_max + delta) *
1828 sizeof (struct interface_info *), MDL);
1829 if (!vec)
1830 return;
1831 memset (&vec [interface_max], 0,
1832 (sizeof (struct interface_info *)) * delta);
1833 interface_max += delta;
1834 if (interface_vector) {
1835 memcpy (vec, interface_vector,
1836 (interface_count *
1837 sizeof (struct interface_info *)));
1838 dfree (interface_vector, MDL);
1840 interface_vector = vec;
1842 interface_reference (&interface_vector [tptr -> index], tptr, MDL);
1843 if (tptr -> index >= interface_count)
1844 interface_count = tptr -> index + 1;
1845 #if defined (TRACING)
1846 trace_interface_register (interface_trace, tptr);
1847 #endif
1850 void interface_snorf (struct interface_info *tmp, int ir)
1852 tmp -> circuit_id = (u_int8_t *)tmp -> name;
1853 tmp -> circuit_id_len = strlen (tmp -> name);
1854 tmp -> remote_id = 0;
1855 tmp -> remote_id_len = 0;
1856 tmp -> flags = ir;
1857 if (interfaces) {
1858 interface_reference (&tmp -> next,
1859 interfaces, MDL);
1860 interface_dereference (&interfaces, MDL);
1862 interface_reference (&interfaces, tmp, MDL);