1 /* $NetBSD: discover.c,v 1.4 2014/07/12 12:09:37 spz Exp $ */
4 Find and identify the network interfaces. */
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.
25 * Redwood City, CA 94063
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 $");
36 #define BSD_COMP /* needed on Solaris for SIOCGLIFNUM */
37 #include <sys/ioctl.h>
44 struct interface_info
*interfaces
, *dummy_interfaces
, *fallback_interface
;
45 int interfaces_invalidated
;
46 int quiet_interface_discovery
;
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,
62 struct iaddr
, struct hardware
*);
65 void (*dhcpv6_packet_handler
)(struct interface_info
*,
67 int, const struct iaddr
*,
72 omapi_object_type_t
*dhcp_type_interface
;
74 trace_type_t
*interface_trace
;
75 trace_type_t
*inpacket_trace
;
76 trace_type_t
*outpacket_trace
;
78 struct interface_info
**interface_vector
;
82 OMAPI_OBJECT_ALLOC (interface
, struct interface_info
, dhcp_type_interface
)
84 isc_result_t
interface_setup ()
87 status
= omapi_object_type_register (&dhcp_type_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
,
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
));
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
);
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
162 # define ISC_HAVE_LIFC_FAMILY 1
163 # define ISC_HAVE_LIFC_FLAGS 1
164 # define LIFCONF lifconf
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
176 # define LIFREQ lifreq
180 # if defined(LIFNAMSIZ)
181 # define IF_NAMESIZE LIFNAMSIZ
182 # elif defined(IFNAMSIZ)
183 # define IF_NAMESIZE IFNAMSIZ
185 # define IF_NAMESIZE 16
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
200 # define ss_family __ss_family
204 #if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
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.
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.
240 begin_iface_scan(struct iface_conf_list
*ifaces
) {
241 #ifdef ISC_PLATFORM_HAVELIFNUM
242 struct lifnum lifnum
;
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");
253 memset(&lifnum
, 0, sizeof(lifnum
));
254 #ifdef ISC_PLATFORM_HAVELIFNUM
255 lifnum
.lifn_family
= AF_UNSPEC
;
258 if (ioctl(ifaces
->sock
, SIOCGLIFNUM
, &lifnum
) < 0) {
259 log_error("Error finding total number of interfaces; %m");
265 #ifdef ISC_PLATFORM_HAVELIFNUM
266 ifaces
->num
= lifnum
.lifn_count
;
268 ifaces
->num
= lifnum
;
272 #endif /* SIOCGLIFNUM */
274 memset(&ifaces
->conf
, 0, sizeof(ifaces
->conf
));
275 #ifdef ISC_HAVE_LIFC_FAMILY
276 ifaces
->conf
.lifc_family
= AF_UNSPEC
;
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
);
298 * Retrieve the next interface.
300 * Returns information in the info structure.
301 * Sets err to 1 if there is an error, otherwise 0.
304 next_iface(struct iface_info
*info
, int *err
, struct iface_conf_list
*ifaces
) {
307 isc_boolean_t foundif
;
308 #if defined(sun) || defined(__linux)
309 /* Pointer used to remove interface aliases. */
316 if (ifaces
->next
>= ifaces
->num
) {
321 p
= ifaces
->conf
.lifc_req
;
324 if (strlen(p
->lifr_name
) >= sizeof(info
->name
)) {
326 log_error("Interface name '%s' too long", p
->lifr_name
);
330 /* Reject if interface address family does not match */
331 if (p
->lifr_addr
.ss_family
!= local_family
) {
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
, ':');
346 #endif /* defined(sun) || defined(__linux) */
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",
360 info
->flags
= tmp
.lifr_flags
;
368 * End scan of interfaces.
371 end_iface_scan(struct iface_conf_list
*ifaces
) {
372 dfree(ifaces
->conf
.lifc_buf
, MDL
);
377 #elif __linux /* !HAVE_SIOCGLIFCONF */
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 */
395 FILE *fp6
; /* input from /proc/net/if_inet6 */
400 * Structure used to return information about a specific interface.
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.
414 begin_iface_scan(struct iface_conf_list
*ifaces
) {
419 ifaces
->fp
= fopen("/proc/net/dev", "r");
420 if (ifaces
->fp
== NULL
) {
421 log_error("Error opening '/proc/net/dev' to list interfaces");
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'");
436 if ((len
<= 0) || (buf
[len
-1] != '\n')) {
437 log_error("Bad header line in '/proc/net/dev'");
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");
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");
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
484 * We use an ioctl() to get the address and flags for each interface.
487 next_iface4(struct iface_info
*info
, int *err
, struct iface_conf_list
*ifaces
) {
495 * Loop exits when we find an interface that has an address, or
496 * when we run out of interfaces.
501 * Read the next line in the file.
503 if (fgets(buf
, sizeof(buf
), ifaces
->fp
) == NULL
) {
504 if (ferror(ifaces
->fp
)) {
506 log_error("Error reading interface "
515 * Make sure the line is a nice,
516 * newline-terminated line.
519 if ((len
<= 0) || (buf
[len
-1] != '\n')) {
520 log_error("Bad line reading interface "
527 * Figure out our name.
529 p
= strrchr(buf
, ':');
531 log_error("Bad line reading interface "
532 "information (no colon)");
538 while (isspace(*name
)) {
543 * Copy our name into our interface structure.
546 if (len
>= sizeof(info
->name
)) {
548 log_error("Interface name '%s' too long", name
);
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
, ':');
561 #ifdef SKIP_DUMMY_INTERFACES
562 } while (strncmp(info
->name
, "dummy", 5) == 0);
567 memset(&tmp
, 0, sizeof(tmp
));
568 strcpy(tmp
.ifr_name
, name
);
569 if (ioctl(ifaces
->sock
, SIOCGIFADDR
, &tmp
) < 0) {
570 if (errno
== EADDRNOTAVAIL
) {
573 log_error("Error getting interface address "
574 "for '%s'; %m", name
);
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",
588 info
->flags
= tmp
.ifr_flags
;
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.
611 next_iface6(struct iface_info
*info
, int *err
, struct iface_conf_list
*ifaces
) {
617 struct sockaddr_in6 addr
;
622 * Read the next line in the file.
624 if (fgets(buf
, sizeof(buf
), ifaces
->fp6
) == NULL
) {
625 if (ferror(ifaces
->fp6
)) {
627 log_error("Error reading IPv6 "
628 "interface information");
636 * Make sure the line is a nice, newline-terminated line.
639 if ((len
<= 0) || (buf
[len
-1] != '\n')) {
640 log_error("Bad line reading IPv6 "
641 "interface information");
647 * Figure out our name.
650 p
= strrchr(buf
, ' ');
652 log_error("Bad line reading IPv6 interface "
653 "information (no space)");
660 * Copy our name into our interface structure.
663 if (len
>= sizeof(info
->name
)) {
665 log_error("IPv6 interface name '%s' too long", name
);
668 strcpy(info
->name
, name
);
670 #ifdef SKIP_DUMMY_INTERFACES
671 } while (strncmp(info
->name
, "dummy", 5) == 0);
677 * Double-check we start with the IPv6 address.
679 for (i
=0; i
<32; i
++) {
680 if (!isxdigit(buf
[i
]) || isupper(buf
[i
])) {
682 log_error("Bad line reading IPv6 interface address "
689 * Load our socket structure.
691 memset(&addr
, 0, sizeof(addr
));
692 addr
.sin6_family
= AF_INET6
;
693 for (i
=0; i
<16; i
++) {
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
));
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
);
712 info
->flags
= tmp
.ifr_flags
;
720 * Retrieve the next interface.
722 * Returns information in the info structure.
723 * Sets err to 1 if there is an error, otherwise 0.
726 next_iface(struct iface_info
*info
, int *err
, struct iface_conf_list
*ifaces
) {
727 if (next_iface4(info
, err
, ifaces
)) {
732 if (local_family
== AF_INET6
)
733 return next_iface6(info
, err
, ifaces
);
740 * End scan of interfaces.
743 end_iface_scan(struct iface_conf_list
*ifaces
) {
749 if (local_family
== AF_INET6
) {
761 * FreeBSD, NetBSD, OpenBSD, and OS X all have the getifaddrs()
764 * The getifaddrs() man page describes the use.
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.
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.
792 begin_iface_scan(struct iface_conf_list
*ifaces
) {
793 if (getifaddrs(&ifaces
->head
) != 0) {
794 log_error("Error getting interfaces; %m");
797 ifaces
->next
= ifaces
->head
;
802 * Retrieve the next interface.
804 * Returns information in the info structure.
805 * Sets err to 1 if there is an error, otherwise 0.
808 next_iface(struct iface_info
*info
, int *err
, struct iface_conf_list
*ifaces
) {
809 if (ifaces
->next
== NULL
) {
813 if (strlen(ifaces
->next
->ifa_name
) >= sizeof(info
->name
)) {
814 log_error("Interface name '%s' too long",
815 ifaces
->next
->ifa_name
);
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
;
829 * End scan of interfaces.
832 end_iface_scan(struct iface_conf_list
*ifaces
) {
833 freeifaddrs(ifaces
->head
);
839 /* XXX: perhaps create drealloc() rather than do it manually */
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 "
853 iface
->address_count
= 0;
854 iface
->address_max
= 4;
855 } else if (iface
->address_count
>= iface
->address_max
) {
859 new_max
= iface
->address_max
+ 4;
860 tmp
= dmalloc(new_max
* sizeof(struct in_addr
), MDL
);
862 log_fatal("Out of memory saving IPv4 address "
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
;
876 /* XXX: perhaps create drealloc() rather than do it manually */
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 "
891 iface
->v6address_count
= 0;
892 iface
->v6address_max
= 8;
893 } else if (iface
->v6address_count
>= iface
->v6address_max
) {
894 struct in6_addr
*tmp
;
897 new_max
= iface
->v6address_max
+ 8;
898 tmp
= dmalloc(new_max
* sizeof(struct in6_addr
), MDL
);
900 log_fatal("Out of memory saving IPv6 address "
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
;
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. */
920 discover_interfaces(int state
) {
921 struct iface_conf_list ifaces
;
922 struct iface_info info
;
925 struct interface_info
*tmp
;
926 struct interface_info
*last
, *next
;
929 char abuf
[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
933 struct subnet
*subnet
;
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
))
950 else if (state
== DISCOVER_UNCONFIGURED
)
951 ir
= INTERFACE_REQUESTED
| INTERFACE_AUTOMATIC
;
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
))
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
)) ||
971 (local_family
== AF_INET6
&&
972 !(info
.flags
& IFF_MULTICAST
)) ||
974 info
.flags
& IFF_LOOPBACK
||
975 info
.flags
& IFF_POINTOPOINT
) && !tmp
) ||
976 (!(info
.flags
& IFF_UP
) &&
977 state
!= DISCOVER_UNCONFIGURED
))
980 /* If there isn't already an interface by this name,
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
;
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
))
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 */
1018 memcpy(addr
.iabuf
, &a
->sin_addr
.s_addr
, addr
.len
);
1019 if (dhcp_interface_setup_hook
) {
1020 (*dhcp_interface_setup_hook
)(tmp
, &addr
);
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
;
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
))
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 */
1045 memcpy(addr
.iabuf
, &a
->sin6_addr
, addr
.len
);
1046 if (dhcp_interface_setup_hook
) {
1047 (*dhcp_interface_setup_hook
)(tmp
, &addr
);
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
) {
1068 tif
= (struct ifreq
*)dmalloc(sizeof(struct ifreq
),
1071 log_fatal("no space for ifp mockup.");
1072 strcpy(tif
->ifr_name
, tmp
->name
);
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
) {
1084 /* Weed out the interfaces that did not have IP addresses. */
1085 tmp
= last
= next
= NULL
;
1087 interface_reference (&tmp
, interfaces
, MDL
);
1090 interface_dereference (&next
, MDL
);
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
);
1097 interface_reference(&tmp
, next
, MDL
);
1100 if ((tmp
-> flags
& INTERFACE_AUTOMATIC
) &&
1101 state
== DISCOVER_REQUESTED
)
1102 tmp
-> flags
&= ~(INTERFACE_AUTOMATIC
|
1103 INTERFACE_REQUESTED
);
1106 if (!(tmp
->flags
& INTERFACE_REQUESTED
)) {
1108 if (!tmp
-> ifp
|| !(tmp
-> flags
& INTERFACE_REQUESTED
)) {
1110 if ((tmp
-> flags
& INTERFACE_REQUESTED
) != ir
)
1111 log_fatal ("%s: not found", tmp
-> name
);
1114 interface_dereference (&interfaces
,
1117 interface_reference (&interfaces
, next
, MDL
);
1119 interface_dereference (&last
-> next
, MDL
);
1121 interface_reference (&last
-> next
,
1125 interface_dereference (&tmp
-> next
, MDL
);
1127 /* Remember the interface in case we need to know
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
);
1137 interface_reference (&tmp
, next
, MDL
);
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).",
1148 (tmp
->addresses
== NULL
) ?
1149 "no IPv4 addresses" :
1150 inet_ntoa(tmp
->addresses
[0]));
1153 if (tmp
->v6addresses
!= NULL
) {
1155 &tmp
->v6addresses
[0],
1159 strcpy(abuf
, "no IPv6 addresses");
1161 log_error("No subnet6 declaration for %s (%s).",
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",
1171 (local_family
!= AF_INET
) ?
1172 "a subnet6 declaration" :
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",
1179 tmp
-> name
, "is attached. **");
1180 log_error ("%s", "");
1183 log_error ("You must write a %s",
1185 (local_family
!= AF_INET
) ?
1186 "subnet6 declaration for this" :
1188 "subnet declaration for this");
1189 log_error ("subnet. You cannot prevent %s",
1191 log_error ("from listening on this subnet %s",
1193 log_fatal ("operating system does not %s.",
1194 "support this capability");
1198 /* Find subnets that don't have valid interface
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
,
1217 /* XXX: should be one */
1218 log_error("%s missing an interface "
1219 "address", tmp
->name
);
1225 /* Flag the index as not having been set, so that the
1226 interface registerer can set it or not as it chooses. */
1229 /* Register the interface... */
1230 if (local_family
== AF_INET
) {
1231 if_register_receive(tmp
);
1232 if_register_send(tmp
);
1235 if ((state
== DISCOVER_SERVER
) ||
1236 (state
== DISCOVER_RELAY
)) {
1237 if_register6(tmp
, 1);
1239 if_register_linklocal6(tmp
);
1244 interface_stash (tmp
);
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",
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",
1257 interface_dereference (&tmp
, MDL
);
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
)
1272 if (tmp
-> rfdesc
== -1)
1274 switch (local_family
) {
1277 status
= omapi_register_io_object((omapi_object_t
*)tmp
,
1279 0, got_one_v6
, 0, 0);
1284 status
= omapi_register_io_object((omapi_object_t
*)tmp
,
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
));
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
))
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
) {
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
)
1332 struct interface_info
*ip
;
1334 if (h
-> type
!= dhcp_type_interface
)
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
,
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
)
1377 struct sockaddr_in from
;
1378 struct hardware hfrom
;
1382 unsigned char packbuf
[4095]; /* Packet input buffer.
1383 Must be as large as largest
1385 struct dhcp_packet packet
;
1387 struct interface_info
*ip
;
1389 if (h
-> type
!= dhcp_type_interface
)
1390 return DHCP_R_INVALIDARG
;
1391 ip
= (struct interface_info
*)h
;
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
;
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
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.
1426 while ((ip
!= NULL
) && (if_nametoindex(ip
->name
) != ifindex
))
1429 return ISC_R_NOTFOUND
;
1433 if (bootp_packet_handler
) {
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
)
1445 return ISC_R_SUCCESS
;
1450 got_one_v6(omapi_object_t
*h
) {
1451 struct sockaddr_in6 from
;
1455 char buf
[65536]; /* maximum size for a UDP packet is 65536 */
1456 struct interface_info
*ip
;
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
);
1468 log_error("receive_packet6() failed on %s: %m", ip
->name
);
1469 return ISC_R_UNEXPECTED
;
1472 /* 0 is 'any' interface. */
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
;
1483 is_unicast
= ISC_TRUE
;
1487 memcpy(ifrom
.iabuf
, &from
.sin6_addr
, ifrom
.len
);
1489 /* Seek forward to find the matching source interface. */
1491 while ((ip
!= NULL
) && (if_nametoindex(ip
->name
) != if_idx
))
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
;
1506 isc_result_t
dhcp_interface_set_value (omapi_object_t
*h
,
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;
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
)
1539 return ISC_R_NOTFOUND
;
1543 isc_result_t
dhcp_interface_get_value (omapi_object_t
*h
,
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
)
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
)
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
)
1613 return ISC_R_NOTFOUND
;
1616 isc_result_t
dhcp_interface_stuff_values (omapi_object_t
*c
,
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
)
1632 if ((interface
->flags
& INTERFACE_REQUESTED
) != 0)
1633 status
= omapi_connection_put_string (c
, "up");
1635 status
= omapi_connection_put_string (c
, "down");
1636 if (status
!= ISC_R_SUCCESS
)
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
)
1647 return ISC_R_SUCCESS
;
1650 isc_result_t
dhcp_interface_lookup (omapi_object_t
**ip
,
1652 omapi_object_t
*ref
)
1654 omapi_value_t
*tv
= (omapi_value_t
*)0;
1655 isc_result_t status
;
1656 struct interface_info
*interface
;
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
)
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
) {
1682 for (interface
= interfaces
; interface
;
1683 interface
= interface
-> next
) {
1684 s
= memchr (interface
-> name
, 0, IFNAMSIZ
);
1686 len
= s
- &interface
-> name
[0];
1689 if ((tv
-> value
-> u
.buffer
.len
== len
&&
1690 !memcmp (interface
-> name
,
1691 (char *)tv
-> value
-> u
.buffer
.value
,
1696 for (interface
= dummy_interfaces
;
1697 interface
; interface
= interface
-> next
) {
1698 s
= memchr (interface
-> name
, 0, IFNAMSIZ
);
1700 len
= s
- &interface
-> name
[0];
1703 if ((tv
-> value
-> u
.buffer
.len
== len
&&
1704 !memcmp (interface
-> name
,
1706 tv
-> value
-> u
.buffer
.value
,
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
) {
1718 omapi_object_dereference (ip
, MDL
);
1719 return ISC_R_NOTFOUND
;
1721 omapi_object_reference (ip
,
1722 (omapi_object_t
*)interface
,
1726 /* If we get to here without finding an interface, no valid key was
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
,
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
)
1744 hp
-> flags
= INTERFACE_REQUESTED
;
1745 status
= interface_reference ((struct interface_info
**)lp
, hp
, MDL
);
1746 interface_dereference (&hp
, MDL
);
1750 isc_result_t
dhcp_interface_remove (omapi_object_t
*lp
,
1753 struct interface_info
*interface
, *ip
, *last
;
1755 interface
= (struct interface_info
*)lp
;
1757 /* remove from interfaces */
1759 for (ip
= interfaces
; ip
; ip
= ip
-> next
) {
1760 if (ip
== interface
) {
1762 interface_dereference (&last
-> next
, MDL
);
1764 interface_reference (&last
-> next
,
1767 interface_dereference (&interfaces
, MDL
);
1769 interface_reference (&interfaces
,
1773 interface_dereference (&ip
-> next
, MDL
);
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
) {
1799 if_deregister6(interface
);
1804 if_deregister_send(interface
);
1805 if_deregister_receive(interface
);
1809 return ISC_R_SUCCESS
;
1812 void interface_stash (struct interface_info
*tptr
)
1814 struct interface_info
**vec
;
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
);
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
,
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
);
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;
1858 interface_reference (&tmp
-> next
,
1860 interface_dereference (&interfaces
, MDL
);
1862 interface_reference (&interfaces
, tmp
, MDL
);