2007-05-08 23:05:22 +00:00
|
|
|
/* discover.c
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
Find and identify the network interfaces. */
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/*
|
2006-02-24 23:16:32 +00:00
|
|
|
* Copyright (c) 2004-2006 by Internet Systems Consortium, Inc. ("ISC")
|
2005-03-17 20:15:29 +00:00
|
|
|
* Copyright (c) 1995-2003 by Internet Software Consortium
|
1998-11-06 00:19:56 +00:00
|
|
|
*
|
2005-03-17 20:15:29 +00:00
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
1998-11-06 00:19:56 +00:00
|
|
|
*
|
2005-03-17 20:15:29 +00:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
|
|
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
1998-11-06 00:19:56 +00:00
|
|
|
*
|
2005-03-17 20:15:29 +00:00
|
|
|
* Internet Systems Consortium, Inc.
|
|
|
|
* 950 Charter Street
|
|
|
|
* Redwood City, CA 94063
|
|
|
|
* <info@isc.org>
|
|
|
|
* http://www.isc.org/
|
2000-03-17 04:00:32 +00:00
|
|
|
*
|
2005-03-17 20:15:29 +00:00
|
|
|
* This software has been written for Internet Systems Consortium
|
2000-03-17 04:00:32 +00:00
|
|
|
* by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
|
2005-03-17 20:15:29 +00:00
|
|
|
* To learn more about Internet Systems Consortium, see
|
2000-03-17 04:00:32 +00:00
|
|
|
* ``http://www.isc.org/''. To learn more about Vixie Enterprises,
|
|
|
|
* see ``http://www.vix.com''. To learn more about Nominum, Inc., see
|
|
|
|
* ``http://www.nominum.com''.
|
1998-11-06 00:19:56 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef lint
|
|
|
|
static char copyright[] =
|
2007-05-08 23:05:22 +00:00
|
|
|
"$Id: discover.c,v 1.53 2007/05/08 23:05:20 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n";
|
1998-11-06 00:19:56 +00:00
|
|
|
#endif /* not lint */
|
|
|
|
|
|
|
|
#include "dhcpd.h"
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
|
1999-02-14 19:04:05 +00:00
|
|
|
struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
|
2001-06-27 00:31:20 +00:00
|
|
|
int interfaces_invalidated;
|
1998-11-06 00:19:56 +00:00
|
|
|
int quiet_interface_discovery;
|
2000-05-01 17:31:19 +00:00
|
|
|
u_int16_t local_port;
|
|
|
|
u_int16_t remote_port;
|
2000-05-16 23:03:49 +00:00
|
|
|
int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
|
|
|
|
int (*dhcp_interface_discovery_hook) (struct interface_info *);
|
2001-04-05 20:50:19 +00:00
|
|
|
isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
|
2000-12-28 23:14:46 +00:00
|
|
|
int (*dhcp_interface_shutdown_hook) (struct interface_info *);
|
2000-05-01 17:31:19 +00:00
|
|
|
|
|
|
|
struct in_addr limited_broadcast;
|
2007-05-08 23:05:22 +00:00
|
|
|
|
|
|
|
int local_family = AF_INET6;
|
2000-05-01 17:31:19 +00:00
|
|
|
struct in_addr local_address;
|
2007-05-08 23:05:22 +00:00
|
|
|
struct in6_addr local_address6;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
void (*bootp_packet_handler) PROTO ((struct interface_info *,
|
1999-10-07 06:36:35 +00:00
|
|
|
struct dhcp_packet *, unsigned,
|
|
|
|
unsigned int,
|
1998-11-06 00:19:56 +00:00
|
|
|
struct iaddr, struct hardware *));
|
2007-05-08 23:05:22 +00:00
|
|
|
void (*dhcpv6_packet_handler)(struct interface_info *,
|
|
|
|
const char *, int,
|
|
|
|
int, const struct iaddr *,
|
|
|
|
isc_boolean_t);
|
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
omapi_object_type_t *dhcp_type_interface;
|
2001-02-12 19:40:05 +00:00
|
|
|
#if defined (TRACING)
|
|
|
|
trace_type_t *interface_trace;
|
|
|
|
trace_type_t *inpacket_trace;
|
|
|
|
trace_type_t *outpacket_trace;
|
|
|
|
#endif
|
|
|
|
struct interface_info **interface_vector;
|
|
|
|
int interface_count;
|
|
|
|
int interface_max;
|
1999-09-08 01:44:08 +00:00
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t interface_setup ()
|
|
|
|
{
|
|
|
|
isc_result_t status;
|
|
|
|
status = omapi_object_type_register (&dhcp_type_interface,
|
|
|
|
"interface",
|
|
|
|
dhcp_interface_set_value,
|
|
|
|
dhcp_interface_get_value,
|
|
|
|
dhcp_interface_destroy,
|
|
|
|
dhcp_interface_signal_handler,
|
|
|
|
dhcp_interface_stuff_values,
|
|
|
|
dhcp_interface_lookup,
|
|
|
|
dhcp_interface_create,
|
|
|
|
dhcp_interface_remove,
|
|
|
|
0, 0, 0,
|
|
|
|
sizeof (struct interface_info),
|
2005-03-17 20:15:29 +00:00
|
|
|
interface_initialize, RC_MISC);
|
2000-12-28 23:14:46 +00:00
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
log_fatal ("Can't register interface object type: %s",
|
|
|
|
isc_result_totext (status));
|
2001-02-12 19:40:05 +00:00
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2001-02-12 19:40:05 +00:00
|
|
|
#if defined (TRACING)
|
|
|
|
void interface_trace_setup ()
|
|
|
|
{
|
|
|
|
interface_trace = trace_type_register ("interface", (void *)0,
|
|
|
|
trace_interface_input,
|
|
|
|
trace_interface_stop, MDL);
|
|
|
|
inpacket_trace = trace_type_register ("inpacket", (void *)0,
|
|
|
|
trace_inpacket_input,
|
|
|
|
trace_inpacket_stop, MDL);
|
|
|
|
outpacket_trace = trace_type_register ("outpacket", (void *)0,
|
|
|
|
trace_outpacket_input,
|
|
|
|
trace_outpacket_stop, MDL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-10-10 22:31:41 +00:00
|
|
|
isc_result_t interface_initialize (omapi_object_t *ipo,
|
|
|
|
const char *file, int line)
|
|
|
|
{
|
|
|
|
struct interface_info *ip = (struct interface_info *)ipo;
|
|
|
|
ip -> rfdesc = ip -> wfdesc = -1;
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/*
|
|
|
|
* Scanning for Interfaces
|
|
|
|
* -----------------------
|
|
|
|
*
|
|
|
|
* To find interfaces, we create an iterator that abstracts out most
|
|
|
|
* of the platform specifics. Use is fairly straightforward:
|
|
|
|
*
|
|
|
|
* - begin_iface_scan() starts the process.
|
|
|
|
* - Use next_iface() until it returns 0.
|
|
|
|
* - end_iface_scan() performs any necessary cleanup.
|
|
|
|
*
|
|
|
|
* We check for errors on each call to next_iface(), which returns a
|
|
|
|
* description of the error as a string if any occurs.
|
|
|
|
*
|
|
|
|
* We currently have code for Solaris and Linux. Other systems need
|
|
|
|
* to have code written.
|
|
|
|
*
|
|
|
|
* NOTE: the long-term goal is to use the interface code from BIND 9.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#if defined(SIOCGLIFNUM)
|
|
|
|
/*
|
|
|
|
* Solaris support
|
|
|
|
* ---------------
|
|
|
|
*
|
|
|
|
* The SIOCGLIFCONF ioctl() are the extension that you need to use
|
|
|
|
* on Solaris to get information about IPv6 addresses.
|
|
|
|
*
|
|
|
|
* Solaris' extended interface is documented in the if_tcp man page.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure holding state about the scan.
|
|
|
|
*/
|
|
|
|
struct iface_conf_list {
|
|
|
|
int sock; /* file descriptor used to get information */
|
|
|
|
int num; /* total number of interfaces */
|
|
|
|
struct lifconf conf; /* structure used to get information */
|
|
|
|
int next; /* next interface to retrieve when iterating */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure used to return information about a specific interface.
|
|
|
|
*/
|
|
|
|
struct iface_info {
|
|
|
|
char name[LIFNAMSIZ]; /* name of the interface, e.g. "bge0" */
|
|
|
|
struct sockaddr_storage addr; /* address information */
|
|
|
|
isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start a scan of interfaces.
|
|
|
|
*
|
|
|
|
* The iface_conf_list structure maintains state for this process.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
begin_iface_scan(struct iface_conf_list *ifaces) {
|
|
|
|
struct lifnum lifnum;
|
|
|
|
|
|
|
|
ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
|
if (ifaces->sock < 0) {
|
|
|
|
log_error("Error creating socket to list interfaces; %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&lifnum, 0, sizeof(lifnum));
|
|
|
|
lifnum.lifn_family = AF_UNSPEC;
|
|
|
|
if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) {
|
|
|
|
log_error("Error finding total number of interfaces; %m");
|
|
|
|
close(ifaces->sock);
|
|
|
|
ifaces->sock = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifaces->num = lifnum.lifn_count;
|
|
|
|
memset(&ifaces->conf, 0, sizeof(ifaces->conf));
|
|
|
|
ifaces->conf.lifc_family = AF_UNSPEC;
|
|
|
|
ifaces->conf.lifc_len = ifaces->num * sizeof(struct lifreq);
|
|
|
|
ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL);
|
|
|
|
if (ifaces->conf.lifc_buf == NULL) {
|
|
|
|
log_fatal("Out of memory getting interface list.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) {
|
|
|
|
log_error("Error getting interfaces configuration list; %m");
|
|
|
|
dfree(ifaces->conf.lifc_buf, MDL);
|
|
|
|
close(ifaces->sock);
|
|
|
|
ifaces->sock = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifaces->next = 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieve the next interface.
|
|
|
|
*
|
|
|
|
* Returns information in the info structure.
|
|
|
|
* Sets err to 1 if there is an error, otherwise 1.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
|
|
|
|
struct lifreq *p;
|
|
|
|
struct lifreq tmp;
|
1998-11-06 00:19:56 +00:00
|
|
|
char *s;
|
1999-09-08 01:44:08 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
do {
|
|
|
|
if (ifaces->next >= ifaces->num) {
|
|
|
|
*err = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
p = ifaces->conf.lifc_req;
|
|
|
|
p += ifaces->next;
|
2001-03-17 02:11:29 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if (strlen(p->lifr_name) >= sizeof(info->name)) {
|
|
|
|
*err = 1;
|
|
|
|
log_error("Interface name '%s' too long", p->lifr_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
strcpy(info->name, p->lifr_name);
|
|
|
|
info->addr = p->lifr_addr;
|
2001-03-17 02:11:29 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
#ifdef ALIAS_NAMES_PERMUTED
|
|
|
|
/* interface aliases look like "eth0:1" or "wlan1:3" */
|
|
|
|
s = strchr(info->name, ':');
|
|
|
|
if (s != NULL) {
|
|
|
|
*s = '\0';
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef SKIP_DUMMY_INTERFACES
|
|
|
|
} while (strncmp(info->name, "dummy", 5) == 0);
|
2001-05-02 06:36:54 +00:00
|
|
|
#else
|
2007-05-08 23:05:22 +00:00
|
|
|
} while (0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
strcpy(tmp.lifr_name, info->name);
|
|
|
|
if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) {
|
|
|
|
log_error("Error getting interface flags for '%s'; %m",
|
|
|
|
p->lifr_name);
|
|
|
|
*err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
info->flags = tmp.lifr_flags;
|
|
|
|
|
|
|
|
ifaces->next++;
|
|
|
|
*err = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End scan of interfaces.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
end_iface_scan(struct iface_conf_list *ifaces) {
|
|
|
|
dfree(ifaces->conf.lifc_buf, MDL);
|
|
|
|
close(ifaces->sock);
|
|
|
|
ifaces->sock = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif __linux /* !HAVE_SIOCGLIFCONF */
|
|
|
|
/*
|
|
|
|
* Linux support
|
|
|
|
* -------------
|
|
|
|
*
|
|
|
|
* In Linux, we use the /proc pseudo-filesystem to get information
|
|
|
|
* about interfaces, along with selected ioctl() calls.
|
|
|
|
*
|
|
|
|
* Linux low level access is documented in the netdevice man page.
|
|
|
|
*/
|
2001-03-17 02:11:29 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/*
|
|
|
|
* Structure holding state about the scan.
|
|
|
|
*/
|
|
|
|
struct iface_conf_list {
|
|
|
|
int sock; /* file descriptor used to get information */
|
|
|
|
FILE *fp; /* input from /proc/net/dev */
|
|
|
|
#ifdef DHCPv6
|
|
|
|
FILE *fp6; /* input from /proc/net/if_inet6 */
|
2001-05-02 06:36:54 +00:00
|
|
|
#endif
|
2007-05-08 23:05:22 +00:00
|
|
|
};
|
2001-03-17 02:11:29 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/*
|
|
|
|
* Structure used to return information about a specific interface.
|
|
|
|
*/
|
|
|
|
struct iface_info {
|
|
|
|
char name[IFNAMSIZ]; /* name of the interface, e.g. "eth0" */
|
|
|
|
struct sockaddr_storage addr; /* address information */
|
|
|
|
isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start a scan of interfaces.
|
|
|
|
*
|
|
|
|
* The iface_conf_list structure maintains state for this process.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
begin_iface_scan(struct iface_conf_list *ifaces) {
|
|
|
|
char buf[256];
|
|
|
|
int len;
|
|
|
|
int i;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
ifaces->fp = fopen(PROCDEV_DEVICE, "r");
|
|
|
|
if (ifaces->fp == NULL) {
|
|
|
|
log_error("Error opening '%s' to list interfaces",
|
|
|
|
PROCDEV_DEVICE);
|
|
|
|
return 0;
|
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/*
|
|
|
|
* The first 2 lines are header information, so read and ignore them.
|
|
|
|
*/
|
|
|
|
for (i=0; i<2; i++) {
|
|
|
|
if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
|
|
|
|
log_error("Error reading headers from '%s'",
|
|
|
|
PROCDEV_DEVICE);
|
|
|
|
fclose(ifaces->fp);
|
|
|
|
ifaces->fp = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
len = strlen(buf);
|
|
|
|
if ((len <= 0) || (buf[len-1] != '\n')) {
|
|
|
|
log_error("Bad header line in '%s'", PROCDEV_DEVICE);
|
|
|
|
fclose(ifaces->fp);
|
|
|
|
ifaces->fp = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
|
if (ifaces->sock < 0) {
|
|
|
|
log_error("Error creating socket to list interfaces; %m");
|
|
|
|
fclose(ifaces->fp);
|
|
|
|
ifaces->fp = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DHCPv6
|
|
|
|
ifaces->fp6 = fopen("/proc/net/if_inet6", "r");
|
|
|
|
if (ifaces->fp6 == NULL) {
|
|
|
|
log_error("Error opening '/proc/net/if_inet6' to "
|
|
|
|
"list IPv6 interfaces; %m");
|
|
|
|
close(ifaces->sock);
|
|
|
|
ifaces->sock = -1;
|
|
|
|
fclose(ifaces->fp);
|
|
|
|
ifaces->fp = NULL;
|
|
|
|
return 0;
|
2001-05-17 19:04:09 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read our IPv4 interfaces from /proc/net/dev.
|
|
|
|
*
|
|
|
|
* The file looks something like this:
|
|
|
|
*
|
|
|
|
* Inter-| Receive ...
|
|
|
|
* face |bytes packets errs drop fifo frame ...
|
|
|
|
* lo: 1580562 4207 0 0 0 0 ...
|
|
|
|
* eth0: 0 0 0 0 0 0 ...
|
|
|
|
* eth1:1801552440 37895 0 14 0 ...
|
|
|
|
*
|
|
|
|
* We only care about the interface name, which is at the start of
|
|
|
|
* each line.
|
|
|
|
*
|
|
|
|
* We use an ioctl() to get the address and flags for each interface.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
next_iface4(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
|
|
|
|
char buf[256];
|
|
|
|
int len;
|
|
|
|
char *p;
|
|
|
|
char *name;
|
|
|
|
struct ifreq tmp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop exits when we find an interface that has an address, or
|
|
|
|
* when we run out of interfaces.
|
|
|
|
*/
|
|
|
|
for (;;) {
|
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* Read the next line in the file.
|
|
|
|
*/
|
|
|
|
if (fgets(buf, sizeof(buf), ifaces->fp) == NULL) {
|
|
|
|
if (ferror(ifaces->fp)) {
|
|
|
|
*err = 1;
|
|
|
|
log_error("Error reading interface "
|
|
|
|
"information");
|
|
|
|
} else {
|
|
|
|
*err = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure the line is a nice,
|
|
|
|
* newline-terminated line.
|
|
|
|
*/
|
|
|
|
len = strlen(buf);
|
|
|
|
if ((len <= 0) || (buf[len-1] != '\n')) {
|
|
|
|
log_error("Bad line reading interface "
|
|
|
|
"information");
|
|
|
|
*err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out our name.
|
|
|
|
*/
|
|
|
|
p = strrchr(buf, ':');
|
|
|
|
if (p == NULL) {
|
|
|
|
log_error("Bad line reading interface "
|
|
|
|
"information (no colon)");
|
|
|
|
*err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*p = '\0';
|
|
|
|
name = buf;
|
|
|
|
while (isspace(*name)) {
|
|
|
|
name++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy our name into our interface structure.
|
|
|
|
*/
|
|
|
|
len = p - name;
|
|
|
|
if (len >= sizeof(info->name)) {
|
|
|
|
*err = 1;
|
|
|
|
log_error("Interface name '%s' too long", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
strcpy(info->name, name);
|
|
|
|
|
|
|
|
#ifdef ALIAS_NAMED_PERMUTED
|
|
|
|
/* interface aliases look like "eth0:1" or "wlan1:3" */
|
|
|
|
s = strchr(info->name, ':');
|
|
|
|
if (s != NULL) {
|
|
|
|
*s = '\0';
|
|
|
|
}
|
2001-05-02 06:36:54 +00:00
|
|
|
#endif
|
2007-05-08 23:05:22 +00:00
|
|
|
|
|
|
|
#ifdef SKIP_DUMMY_INTERFACES
|
|
|
|
} while (strncmp(info->name, "dummy", 5) == 0);
|
|
|
|
#else
|
|
|
|
} while (0);
|
2001-05-02 06:36:54 +00:00
|
|
|
#endif
|
2007-05-08 23:05:22 +00:00
|
|
|
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
strcpy(tmp.ifr_name, name);
|
|
|
|
if (ioctl(ifaces->sock, SIOCGIFADDR, &tmp) < 0) {
|
|
|
|
if (errno == EADDRNOTAVAIL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
log_error("Error getting interface address "
|
|
|
|
"for '%s'; %m", name);
|
|
|
|
*err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
memcpy(&info->addr, &tmp.ifr_addr, sizeof(tmp.ifr_addr));
|
|
|
|
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
strcpy(tmp.ifr_name, name);
|
|
|
|
if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
|
|
|
|
log_error("Error getting interface flags for '%s'; %m",
|
|
|
|
name);
|
|
|
|
*err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
info->flags = tmp.ifr_flags;
|
|
|
|
|
|
|
|
*err = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DHCPv6
|
|
|
|
/*
|
|
|
|
* Read our IPv6 interfaces from /proc/net/if_inet6.
|
|
|
|
*
|
|
|
|
* The file looks something like this:
|
|
|
|
*
|
|
|
|
* fe80000000000000025056fffec00008 05 40 20 80 vmnet8
|
|
|
|
* 00000000000000000000000000000001 01 80 10 80 lo
|
|
|
|
* fe80000000000000025056fffec00001 06 40 20 80 vmnet1
|
|
|
|
* 200108881936000202166ffffe497d9b 03 40 00 00 eth1
|
|
|
|
* fe8000000000000002166ffffe497d9b 03 40 20 80 eth1
|
|
|
|
*
|
|
|
|
* We get IPv6 address from the start, the interface name from the end,
|
|
|
|
* and ioctl() to get flags.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
next_iface6(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
|
|
|
|
char buf[256];
|
|
|
|
int len;
|
|
|
|
char *p;
|
|
|
|
char *name;
|
|
|
|
int i;
|
|
|
|
struct sockaddr_in6 addr;
|
|
|
|
struct ifreq tmp;
|
|
|
|
|
|
|
|
do {
|
|
|
|
/*
|
|
|
|
* Read the next line in the file.
|
|
|
|
*/
|
|
|
|
if (fgets(buf, sizeof(buf), ifaces->fp6) == NULL) {
|
|
|
|
if (ferror(ifaces->fp6)) {
|
|
|
|
*err = 1;
|
|
|
|
log_error("Error reading IPv6 "
|
|
|
|
"interface information");
|
|
|
|
} else {
|
|
|
|
*err = 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure the line is a nice, newline-terminated line.
|
|
|
|
*/
|
|
|
|
len = strlen(buf);
|
|
|
|
if ((len <= 0) || (buf[len-1] != '\n')) {
|
|
|
|
log_error("Bad line reading IPv6 "
|
|
|
|
"interface information");
|
|
|
|
*err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out our name.
|
|
|
|
*/
|
|
|
|
buf[--len] = '\0';
|
|
|
|
p = strrchr(buf, ' ');
|
|
|
|
if (p == NULL) {
|
|
|
|
log_error("Bad line reading IPv6 interface "
|
|
|
|
"information (no space)");
|
|
|
|
*err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
name = p+1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy our name into our interface structure.
|
|
|
|
*/
|
|
|
|
len = strlen(name);
|
|
|
|
if (len >= sizeof(info->name)) {
|
|
|
|
*err = 1;
|
|
|
|
log_error("IPv6 interface name '%s' too long", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
strcpy(info->name, name);
|
|
|
|
|
|
|
|
#ifdef SKIP_DUMMY_INTERFACES
|
|
|
|
} while (strncmp(info->name, "dummy", 5) == 0);
|
|
|
|
#else
|
|
|
|
} while (0);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Double-check we start with the IPv6 address.
|
|
|
|
*/
|
|
|
|
for (i=0; i<32; i++) {
|
|
|
|
if (!isxdigit(buf[i]) || isupper(buf[i])) {
|
|
|
|
*err = 1;
|
|
|
|
log_error("Bad line reading IPv6 interface address "
|
|
|
|
"for '%s'", name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Load our socket structure.
|
|
|
|
*/
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
addr.sin6_family = AF_INET6;
|
|
|
|
for (i=0; i<16; i++) {
|
|
|
|
unsigned char byte;
|
|
|
|
static const char hex[] = "0123456789abcdef";
|
|
|
|
byte = ((index(hex, buf[i * 2]) - hex) << 4) |
|
|
|
|
(index(hex, buf[i * 2 + 1]) - hex);
|
|
|
|
addr.sin6_addr.s6_addr[i] = byte;
|
|
|
|
}
|
|
|
|
memcpy(&info->addr, &addr, sizeof(addr));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get our flags.
|
|
|
|
*/
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
|
|
|
strcpy(tmp.ifr_name, name);
|
|
|
|
if (ioctl(ifaces->sock, SIOCGIFFLAGS, &tmp) < 0) {
|
|
|
|
log_error("Error getting interface flags for '%s'; %m", name);
|
|
|
|
*err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
info->flags = tmp.ifr_flags;
|
|
|
|
|
|
|
|
*err = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif /* DHCPv6 */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieve the next interface.
|
|
|
|
*
|
|
|
|
* Returns information in the info structure.
|
|
|
|
* Sets err to 1 if there is an error, otherwise 1.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
|
|
|
|
if (next_iface4(info, err, ifaces)) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#ifdef DHCPv6
|
|
|
|
if (!(*err)) {
|
|
|
|
return next_iface6(info, err, ifaces);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End scan of interfaces.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
end_iface_scan(struct iface_conf_list *ifaces) {
|
|
|
|
fclose(ifaces->fp);
|
|
|
|
ifaces->fp = NULL;
|
|
|
|
close(ifaces->sock);
|
|
|
|
ifaces->sock = -1;
|
|
|
|
#ifdef DHCPv6
|
|
|
|
fclose(ifaces->fp6);
|
|
|
|
ifaces->fp6 = NULL;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
/* XXX: need to define non-Solaris, non-Linux iterators */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* XXX: perhaps create drealloc() rather than do it manually */
|
|
|
|
void
|
|
|
|
add_ipv4_addr_to_interface(struct interface_info *iface,
|
|
|
|
const struct in_addr *addr) {
|
|
|
|
/*
|
|
|
|
* We don't expect a lot of addresses per IPv4 interface, so
|
|
|
|
* we use 4, as our "chunk size" for collecting addresses.
|
|
|
|
*/
|
|
|
|
if (iface->addresses == NULL) {
|
|
|
|
iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL);
|
|
|
|
if (iface->addresses == NULL) {
|
|
|
|
log_fatal("Out of memory saving IPv4 address "
|
|
|
|
"on interface.");
|
|
|
|
}
|
|
|
|
iface->address_count = 0;
|
|
|
|
iface->address_max = 4;
|
|
|
|
} else if (iface->address_count >= iface->address_max) {
|
|
|
|
struct in_addr *tmp;
|
|
|
|
int new_max;
|
|
|
|
|
|
|
|
new_max = iface->address_max + 4;
|
|
|
|
tmp = dmalloc(new_max * sizeof(struct in_addr), MDL);
|
|
|
|
if (tmp == NULL) {
|
|
|
|
log_fatal("Out of memory saving IPv4 address "
|
|
|
|
"on interface.");
|
|
|
|
}
|
|
|
|
memcpy(tmp,
|
|
|
|
iface->addresses,
|
|
|
|
iface->address_max * sizeof(struct in_addr));
|
|
|
|
dfree(iface->addresses, MDL);
|
|
|
|
iface->addresses = tmp;
|
|
|
|
iface->address_max = new_max;
|
|
|
|
}
|
|
|
|
iface->addresses[iface->address_count++] = *addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: perhaps create drealloc() rather than do it manually */
|
|
|
|
void
|
|
|
|
add_ipv6_addr_to_interface(struct interface_info *iface,
|
|
|
|
const struct in6_addr *addr) {
|
|
|
|
/*
|
|
|
|
* Each IPv6 interface will have at least two IPv6 addresses,
|
|
|
|
* and likely quite a few more. So we use 8, as our "chunk size" for
|
|
|
|
* collecting addresses.
|
|
|
|
*/
|
|
|
|
if (iface->v6addresses == NULL) {
|
|
|
|
iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL);
|
|
|
|
if (iface->v6addresses == NULL) {
|
|
|
|
log_fatal("Out of memory saving IPv6 address "
|
|
|
|
"on interface.");
|
|
|
|
}
|
|
|
|
iface->v6address_count = 0;
|
|
|
|
iface->v6address_max = 8;
|
|
|
|
} else if (iface->v6address_count >= iface->v6address_max) {
|
|
|
|
struct in6_addr *tmp;
|
|
|
|
int new_max;
|
|
|
|
|
|
|
|
new_max = iface->v6address_max + 8;
|
|
|
|
tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL);
|
|
|
|
if (tmp == NULL) {
|
|
|
|
log_fatal("Out of memory saving IPv6 address "
|
|
|
|
"on interface.");
|
|
|
|
}
|
|
|
|
memcpy(tmp,
|
|
|
|
iface->v6addresses,
|
|
|
|
iface->v6address_max * sizeof(struct in6_addr));
|
|
|
|
dfree(iface->v6addresses, MDL);
|
|
|
|
iface->v6addresses = tmp;
|
|
|
|
iface->v6address_max = new_max;
|
|
|
|
}
|
|
|
|
iface->v6addresses[iface->v6address_count++] = *addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces.
|
|
|
|
For each interface that's of type INET and not the loopback interface,
|
|
|
|
register that interface with the network I/O software, figure out what
|
|
|
|
subnet it's on, and add it to the list of interfaces. */
|
|
|
|
|
|
|
|
void
|
|
|
|
discover_interfaces(int state) {
|
|
|
|
struct iface_conf_list ifaces;
|
|
|
|
struct iface_info info;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
struct interface_info *tmp, *ip;
|
|
|
|
struct interface_info *last, *next;
|
|
|
|
|
|
|
|
char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
|
|
|
|
|
|
|
|
struct subnet *subnet;
|
|
|
|
int ir;
|
|
|
|
isc_result_t status;
|
|
|
|
int wifcount = 0;
|
|
|
|
|
|
|
|
static int setup_fallback = 0;
|
|
|
|
|
|
|
|
if (!begin_iface_scan(&ifaces)) {
|
|
|
|
log_fatal("Can't get list of interfaces.");
|
2000-09-04 22:27:41 +00:00
|
|
|
}
|
2001-05-02 06:36:54 +00:00
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
/* If we already have a list of interfaces, and we're running as
|
|
|
|
a DHCP server, the interfaces were requested. */
|
|
|
|
if (interfaces && (state == DISCOVER_SERVER ||
|
|
|
|
state == DISCOVER_RELAY ||
|
|
|
|
state == DISCOVER_REQUESTED))
|
|
|
|
ir = 0;
|
|
|
|
else if (state == DISCOVER_UNCONFIGURED)
|
|
|
|
ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC;
|
|
|
|
else
|
|
|
|
ir = INTERFACE_REQUESTED;
|
|
|
|
|
1999-02-14 19:04:05 +00:00
|
|
|
/* Cycle through the list of interfaces looking for IP addresses. */
|
2007-05-08 23:05:22 +00:00
|
|
|
while (next_iface(&info, &err, &ifaces)) {
|
1998-11-06 00:19:56 +00:00
|
|
|
|
1998-11-11 07:50:51 +00:00
|
|
|
/* See if we've seen an interface that matches this one. */
|
2007-05-08 23:05:22 +00:00
|
|
|
for (tmp = interfaces; tmp; tmp = tmp->next) {
|
|
|
|
if (!strcmp(tmp->name, info.name))
|
1998-11-11 07:50:51 +00:00
|
|
|
break;
|
2007-05-08 23:05:22 +00:00
|
|
|
}
|
1998-11-11 07:50:51 +00:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* Skip non broadcast interfaces (plus loopback and
|
|
|
|
point-to-point in case an OS incorrectly marks them
|
|
|
|
as broadcast). Also skip down interfaces unless we're
|
|
|
|
trying to get a list of configurable interfaces. */
|
2007-05-08 23:05:22 +00:00
|
|
|
if (((!(info.flags & IFF_BROADCAST) ||
|
|
|
|
info.flags & IFF_LOOPBACK ||
|
|
|
|
info.flags & IFF_POINTOPOINT) && !tmp) ||
|
|
|
|
(!(info.flags & IFF_UP) &&
|
1998-11-06 00:19:56 +00:00
|
|
|
state != DISCOVER_UNCONFIGURED))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* If there isn't already an interface by this name,
|
|
|
|
allocate one. */
|
2007-05-08 23:05:22 +00:00
|
|
|
if (tmp == NULL) {
|
|
|
|
status = interface_allocate(&tmp, MDL);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
log_fatal("Error allocating interface %s: %s",
|
|
|
|
info.name, isc_result_totext(status));
|
|
|
|
}
|
|
|
|
strcpy(tmp->name, info.name);
|
|
|
|
interface_snorf(tmp, ir);
|
|
|
|
interface_dereference(&tmp, MDL);
|
2001-02-12 19:40:05 +00:00
|
|
|
tmp = interfaces; /* XXX */
|
2000-01-28 20:30:37 +00:00
|
|
|
}
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if (dhcp_interface_discovery_hook) {
|
|
|
|
(*dhcp_interface_discovery_hook)(tmp);
|
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
/* If we have the capability, extract link information
|
2007-05-08 23:05:22 +00:00
|
|
|
and record it in. */
|
1999-02-25 23:30:43 +00:00
|
|
|
#ifdef HAVE_AF_LINK
|
2007-05-08 23:05:22 +00:00
|
|
|
if (info.addr.ss_family == AF_LINK) {
|
|
|
|
struct sockaddr_dl *d = (struct sockaddr_dl*)&info.addr;
|
|
|
|
tmp->hw_address.hlen = d->sdl_alen;
|
|
|
|
tmp->hw_address.hbuf[0] = HTYPE_ETHER; /* XXX */
|
|
|
|
memcpy(&tmp->hw_address.hbuf[1],
|
|
|
|
LLADDR(d),
|
|
|
|
tmp->hw_address.hlen);
|
|
|
|
tmp->hw_address.hlen++; /* for type. */
|
1998-11-06 00:19:56 +00:00
|
|
|
} else
|
|
|
|
#endif /* AF_LINK */
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if ((info.addr.ss_family == AF_INET) &&
|
|
|
|
(local_family == AF_INET)) {
|
|
|
|
struct sockaddr_in *a = (struct sockaddr_in*)&info.addr;
|
1998-11-06 00:19:56 +00:00
|
|
|
struct iaddr addr;
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/* We don't want the loopback interface. */
|
|
|
|
if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) &&
|
|
|
|
((tmp->flags & INTERFACE_AUTOMATIC) &&
|
|
|
|
state == DISCOVER_SERVER))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* If the only address we have is 0.0.0.0, we
|
|
|
|
shouldn't consider the interface configured. */
|
|
|
|
if (a->sin_addr.s_addr != htonl(INADDR_ANY))
|
|
|
|
tmp->configured = 1;
|
|
|
|
|
|
|
|
add_ipv4_addr_to_interface(tmp, &a->sin_addr);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: We don't have ifreq in Solaris-land if we want IPv6. Fortunately,
|
|
|
|
* we don't actually need this for anything on Solaris.
|
|
|
|
*/
|
|
|
|
#if 0
|
|
|
|
/* If this is the first real IP address we've
|
|
|
|
found, keep a pointer to ifreq structure in
|
|
|
|
which we found it. */
|
|
|
|
if (!tmp -> ifp) {
|
|
|
|
#ifdef HAVE_SA_LEN
|
|
|
|
unsigned len = ((sizeof ifp -> ifr_name) +
|
|
|
|
ifp -> ifr_addr.sa_len);
|
|
|
|
#else
|
|
|
|
unsigned len = sizeof *ifp;
|
|
|
|
#endif
|
|
|
|
tif = (struct ifreq *)dmalloc (len, MDL);
|
|
|
|
if (!tif)
|
|
|
|
log_fatal ("no space for ifp.");
|
|
|
|
memcpy (tif, ifp, len);
|
|
|
|
tmp -> ifp = tif;
|
|
|
|
}
|
|
|
|
#endif /* 0 */
|
|
|
|
|
|
|
|
/* invoke the setup hook */
|
|
|
|
addr.len = 4;
|
|
|
|
memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len);
|
|
|
|
if (dhcp_interface_setup_hook) {
|
|
|
|
(*dhcp_interface_setup_hook)(tmp, &addr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ((info.addr.ss_family == AF_INET6) &&
|
|
|
|
(local_family == AF_INET6)) {
|
|
|
|
struct sockaddr_in6 *a =
|
|
|
|
(struct sockaddr_in6*)&info.addr;
|
|
|
|
struct iaddr addr;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/* We don't want the loopback interface. */
|
2007-05-08 23:05:22 +00:00
|
|
|
if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) &&
|
|
|
|
((tmp->flags & INTERFACE_AUTOMATIC) &&
|
1999-09-08 01:44:08 +00:00
|
|
|
state == DISCOVER_SERVER))
|
2006-08-09 14:57:48 +00:00
|
|
|
continue;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/* If the only address we have is 0.0.0.0, we
|
|
|
|
shouldn't consider the interface configured. */
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
|
|
|
|
tmp->configured = 1;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
add_ipv6_addr_to_interface(tmp, &a->sin6_addr);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX: We don't have ifreq in Solaris-land if we want IPv6. Fortunately,
|
|
|
|
* we don't actually need this for anything on Solaris.
|
|
|
|
*/
|
|
|
|
#if 0
|
1998-11-06 00:19:56 +00:00
|
|
|
/* If this is the first real IP address we've
|
|
|
|
found, keep a pointer to ifreq structure in
|
|
|
|
which we found it. */
|
|
|
|
if (!tmp -> ifp) {
|
|
|
|
#ifdef HAVE_SA_LEN
|
1999-10-07 06:36:35 +00:00
|
|
|
unsigned len = ((sizeof ifp -> ifr_name) +
|
|
|
|
ifp -> ifr_addr.sa_len);
|
1998-11-06 00:19:56 +00:00
|
|
|
#else
|
1999-10-07 06:36:35 +00:00
|
|
|
unsigned len = sizeof *ifp;
|
1998-11-06 00:19:56 +00:00
|
|
|
#endif
|
2000-01-26 14:56:18 +00:00
|
|
|
tif = (struct ifreq *)dmalloc (len, MDL);
|
1998-11-06 00:19:56 +00:00
|
|
|
if (!tif)
|
1999-09-08 01:44:08 +00:00
|
|
|
log_fatal ("no space for ifp.");
|
1998-11-06 00:19:56 +00:00
|
|
|
memcpy (tif, ifp, len);
|
|
|
|
tmp -> ifp = tif;
|
2006-08-09 14:57:48 +00:00
|
|
|
tmp -> primary_address = foo.sin_addr;
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
2007-05-08 23:05:22 +00:00
|
|
|
#endif /* 0 */
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/* invoke the setup hook */
|
|
|
|
addr.len = 16;
|
|
|
|
memcpy(addr.iabuf, &a->sin6_addr, addr.len);
|
|
|
|
if (dhcp_interface_setup_hook) {
|
|
|
|
(*dhcp_interface_setup_hook)(tmp, &addr);
|
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if (err) {
|
|
|
|
log_fatal("Error getting interface information.");
|
|
|
|
}
|
|
|
|
|
|
|
|
end_iface_scan(&ifaces);
|
2000-09-04 22:27:41 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
#if 0
|
1999-02-14 19:04:05 +00:00
|
|
|
#if defined (LINUX_SLASHPROC_DISCOVERY)
|
2000-05-16 23:03:49 +00:00
|
|
|
/* On Linux, interfaces that don't have IP addresses don't
|
|
|
|
show up in the SIOCGIFCONF syscall. This only matters for
|
|
|
|
the DHCP client, of course - the relay agent and server
|
|
|
|
should only care about interfaces that are configured with
|
|
|
|
IP addresses anyway.
|
1999-02-14 19:04:05 +00:00
|
|
|
|
|
|
|
The PROCDEV_DEVICE (/proc/net/dev) is a kernel-supplied file
|
|
|
|
that, when read, prints a human readable network status. We
|
|
|
|
extract the names of the network devices by skipping the first
|
|
|
|
two lines (which are header) and then parsing off everything
|
|
|
|
up to the colon in each subsequent line - these lines start
|
|
|
|
with the interface name, then a colon, then a bunch of
|
2000-05-16 23:03:49 +00:00
|
|
|
statistics. */
|
1999-02-14 19:04:05 +00:00
|
|
|
|
|
|
|
if (state == DISCOVER_UNCONFIGURED) {
|
|
|
|
FILE *proc_dev;
|
|
|
|
char buffer [256];
|
|
|
|
int skip = 2;
|
|
|
|
|
|
|
|
proc_dev = fopen (PROCDEV_DEVICE, "r");
|
|
|
|
if (!proc_dev)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_fatal ("%s: %m", PROCDEV_DEVICE);
|
1999-02-14 19:04:05 +00:00
|
|
|
|
|
|
|
while (fgets (buffer, sizeof buffer, proc_dev)) {
|
|
|
|
char *name = buffer;
|
|
|
|
char *sep;
|
|
|
|
|
|
|
|
/* Skip the first two blocks, which are header
|
|
|
|
lines. */
|
|
|
|
if (skip) {
|
|
|
|
--skip;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sep = strrchr (buffer, ':');
|
|
|
|
if (sep)
|
|
|
|
*sep = '\0';
|
|
|
|
while (*name == ' ')
|
|
|
|
name++;
|
|
|
|
|
|
|
|
/* See if we've seen an interface that matches
|
|
|
|
this one. */
|
|
|
|
for (tmp = interfaces; tmp; tmp = tmp -> next)
|
|
|
|
if (!strcmp (tmp -> name, name))
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* If we found one, nothing more to do.. */
|
|
|
|
if (tmp)
|
|
|
|
continue;
|
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
strncpy (ifr.ifr_name, name, IFNAMSIZ);
|
|
|
|
|
|
|
|
/* Skip non broadcast interfaces (plus loopback and
|
|
|
|
* point-to-point in case an OS incorrectly marks them
|
|
|
|
* as broadcast).
|
|
|
|
*/
|
|
|
|
if ((ioctl (sock, SIOCGIFFLAGS, &ifr) < 0) ||
|
|
|
|
(!(ifr.ifr_flags & IFF_BROADCAST)) ||
|
|
|
|
(ifr.ifr_flags & IFF_LOOPBACK ) ||
|
|
|
|
(ifr.ifr_flags & IFF_POINTOPOINT))
|
|
|
|
continue;
|
|
|
|
|
1999-02-14 19:04:05 +00:00
|
|
|
/* Otherwise, allocate one. */
|
2000-05-16 23:03:49 +00:00
|
|
|
tmp = (struct interface_info *)0;
|
|
|
|
status = interface_allocate (&tmp, MDL);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
log_fatal ("Can't allocate interface %s: %s",
|
|
|
|
name, isc_result_totext (status));
|
1999-02-14 19:04:05 +00:00
|
|
|
tmp -> flags = ir;
|
2001-06-27 00:31:20 +00:00
|
|
|
strncpy (tmp -> name, name, IFNAMSIZ);
|
2002-06-09 22:49:51 +00:00
|
|
|
if (interfaces) {
|
|
|
|
interface_reference (&tmp -> next,
|
|
|
|
interfaces, MDL);
|
|
|
|
interface_dereference (&interfaces, MDL);
|
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
interface_reference (&interfaces, tmp, MDL);
|
|
|
|
interface_dereference (&tmp, MDL);
|
|
|
|
tmp = interfaces;
|
|
|
|
|
2000-05-17 16:04:26 +00:00
|
|
|
if (dhcp_interface_discovery_hook)
|
|
|
|
(*dhcp_interface_discovery_hook) (tmp);
|
2000-05-16 23:03:49 +00:00
|
|
|
|
1999-02-14 19:04:05 +00:00
|
|
|
}
|
|
|
|
fclose (proc_dev);
|
|
|
|
}
|
|
|
|
#endif
|
2007-05-08 23:05:22 +00:00
|
|
|
#endif /* 0 */
|
1999-02-14 19:04:05 +00:00
|
|
|
|
|
|
|
/* Now cycle through all the interfaces we found, looking for
|
|
|
|
hardware addresses. */
|
2007-05-08 23:05:22 +00:00
|
|
|
/* XXX: The dlpi interface code will get this information in Solaris */
|
|
|
|
#if 0
|
1999-02-25 23:30:43 +00:00
|
|
|
#if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK)
|
2007-05-08 23:05:22 +00:00
|
|
|
for (tmp = interfaces; tmp != NULL; tmp = tmp->next) {
|
1999-02-14 19:04:05 +00:00
|
|
|
struct ifreq ifr;
|
|
|
|
struct sockaddr sa;
|
|
|
|
int b, sk;
|
|
|
|
|
|
|
|
if (!tmp -> ifp) {
|
|
|
|
/* Make up an ifreq structure. */
|
2000-01-26 14:56:18 +00:00
|
|
|
tif = (struct ifreq *)dmalloc (sizeof (struct ifreq),
|
|
|
|
MDL);
|
1999-02-14 19:04:05 +00:00
|
|
|
if (!tif)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_fatal ("no space to remember ifp.");
|
1999-02-14 19:04:05 +00:00
|
|
|
memset (tif, 0, sizeof (struct ifreq));
|
|
|
|
strcpy (tif -> ifr_name, tmp -> name);
|
|
|
|
tmp -> ifp = tif;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read the hardware address from this interface. */
|
|
|
|
ifr = *tmp -> ifp;
|
|
|
|
if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
sa = *(struct sockaddr *)&ifr.ifr_hwaddr;
|
|
|
|
|
|
|
|
switch (sa.sa_family) {
|
1999-02-25 23:30:43 +00:00
|
|
|
#ifdef HAVE_ARPHRD_TUNNEL
|
|
|
|
case ARPHRD_TUNNEL:
|
|
|
|
/* ignore tunnel interfaces. */
|
|
|
|
#endif
|
1999-03-26 19:19:46 +00:00
|
|
|
#ifdef HAVE_ARPHRD_ROSE
|
|
|
|
case ARPHRD_ROSE:
|
|
|
|
#endif
|
2006-02-24 23:16:32 +00:00
|
|
|
#ifdef HAVE_ARPHRD_IRDA
|
|
|
|
case ARPHRD_IRDA:
|
|
|
|
/* ignore infrared interfaces. */
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ARPHRD_SIT
|
|
|
|
case ARPHRD_SIT:
|
|
|
|
/* ignore IPv6-in-IPv4 interfaces. */
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ARPHRD_IEEE1394
|
|
|
|
case ARPHRD_IEEE1394:
|
|
|
|
/* ignore IEEE1394 interfaces. */
|
|
|
|
#endif
|
1999-02-25 23:30:43 +00:00
|
|
|
#ifdef HAVE_ARPHRD_LOOPBACK
|
1999-02-14 19:04:05 +00:00
|
|
|
case ARPHRD_LOOPBACK:
|
|
|
|
/* ignore loopback interface */
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
case ARPHRD_ETHER:
|
2000-01-25 01:04:21 +00:00
|
|
|
tmp -> hw_address.hlen = 7;
|
|
|
|
tmp -> hw_address.hbuf [0] = ARPHRD_ETHER;
|
|
|
|
memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
|
1999-02-14 19:04:05 +00:00
|
|
|
break;
|
|
|
|
|
1999-03-26 19:19:46 +00:00
|
|
|
#ifndef HAVE_ARPHRD_IEEE802
|
1999-02-14 19:04:05 +00:00
|
|
|
# define ARPHRD_IEEE802 HTYPE_IEEE802
|
2001-04-09 01:03:14 +00:00
|
|
|
#endif
|
|
|
|
#if defined (HAVE_ARPHRD_IEEE802_TR)
|
|
|
|
case ARPHRD_IEEE802_TR:
|
1999-02-14 19:04:05 +00:00
|
|
|
#endif
|
|
|
|
case ARPHRD_IEEE802:
|
2000-01-25 01:04:21 +00:00
|
|
|
tmp -> hw_address.hlen = 7;
|
|
|
|
tmp -> hw_address.hbuf [0] = ARPHRD_IEEE802;
|
|
|
|
memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
|
1999-02-14 19:04:05 +00:00
|
|
|
break;
|
|
|
|
|
1999-03-26 19:19:46 +00:00
|
|
|
#ifndef HAVE_ARPHRD_FDDI
|
1999-02-14 19:04:05 +00:00
|
|
|
# define ARPHRD_FDDI HTYPE_FDDI
|
|
|
|
#endif
|
|
|
|
case ARPHRD_FDDI:
|
2000-01-25 01:04:21 +00:00
|
|
|
tmp -> hw_address.hlen = 17;
|
|
|
|
tmp -> hw_address.hbuf [0] = HTYPE_FDDI; /* XXX */
|
|
|
|
memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 16);
|
1999-02-14 19:04:05 +00:00
|
|
|
break;
|
|
|
|
|
1999-02-25 23:30:43 +00:00
|
|
|
#ifdef HAVE_ARPHRD_METRICOM
|
1999-02-14 19:04:05 +00:00
|
|
|
case ARPHRD_METRICOM:
|
2000-01-25 01:04:21 +00:00
|
|
|
tmp -> hw_address.hlen = 7;
|
|
|
|
tmp -> hw_address.hbuf [0] = ARPHRD_METRICOM;
|
|
|
|
memcpy (&tmp -> hw_address.hbuf [0], sa.sa_data, 6);
|
1999-03-26 19:19:46 +00:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_ARPHRD_AX25
|
|
|
|
case ARPHRD_AX25:
|
2000-01-25 01:04:21 +00:00
|
|
|
tmp -> hw_address.hlen = 7;
|
|
|
|
tmp -> hw_address.hbuf [0] = ARPHRD_AX25;
|
|
|
|
memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
|
1999-03-26 19:19:46 +00:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_ARPHRD_NETROM
|
|
|
|
case ARPHRD_NETROM:
|
2000-01-25 01:04:21 +00:00
|
|
|
tmp -> hw_address.hlen = 7;
|
|
|
|
tmp -> hw_address.hbuf [0] = ARPHRD_NETROM;
|
|
|
|
memcpy (&tmp -> hw_address.hbuf [1], sa.sa_data, 6);
|
1999-02-14 19:04:05 +00:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
default:
|
1999-03-25 21:57:30 +00:00
|
|
|
log_error ("%s: unknown hardware address type %d",
|
|
|
|
ifr.ifr_name, sa.sa_family);
|
|
|
|
break;
|
1999-02-14 19:04:05 +00:00
|
|
|
}
|
|
|
|
}
|
1999-02-25 23:30:43 +00:00
|
|
|
#endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */
|
2007-05-08 23:05:22 +00:00
|
|
|
#endif /* 0 */
|
1999-02-14 19:04:05 +00:00
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
/* If we're just trying to get a list of interfaces that we might
|
|
|
|
be able to configure, we can quit now. */
|
2000-02-15 20:40:36 +00:00
|
|
|
if (state == DISCOVER_UNCONFIGURED) {
|
1998-11-06 00:19:56 +00:00
|
|
|
return;
|
2000-02-15 20:40:36 +00:00
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/* Weed out the interfaces that did not have IP addresses. */
|
2007-05-08 23:05:22 +00:00
|
|
|
tmp = last = next = NULL;
|
2000-05-16 23:03:49 +00:00
|
|
|
if (interfaces)
|
|
|
|
interface_reference (&tmp, interfaces, MDL);
|
|
|
|
while (tmp) {
|
|
|
|
if (next)
|
|
|
|
interface_dereference (&next, MDL);
|
|
|
|
if (tmp -> next)
|
|
|
|
interface_reference (&next, tmp -> next, MDL);
|
2000-01-28 20:30:37 +00:00
|
|
|
/* skip interfaces that are running already */
|
2005-03-17 20:15:29 +00:00
|
|
|
if (tmp -> flags & INTERFACE_RUNNING) {
|
|
|
|
interface_dereference(&tmp, MDL);
|
|
|
|
if(next)
|
|
|
|
interface_reference(&tmp, next, MDL);
|
2000-01-28 20:30:37 +00:00
|
|
|
continue;
|
2005-03-17 20:15:29 +00:00
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
|
|
|
|
state == DISCOVER_REQUESTED)
|
|
|
|
tmp -> flags &= ~(INTERFACE_AUTOMATIC |
|
|
|
|
INTERFACE_REQUESTED);
|
2007-05-08 23:05:22 +00:00
|
|
|
/* XXX: no ifp in Solaris */
|
|
|
|
/* if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {*/
|
|
|
|
if (!(tmp->flags & INTERFACE_REQUESTED)) {
|
1998-11-06 00:19:56 +00:00
|
|
|
if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_fatal ("%s: not found", tmp -> name);
|
2000-05-16 23:03:49 +00:00
|
|
|
if (!last) {
|
|
|
|
if (interfaces)
|
|
|
|
interface_dereference (&interfaces,
|
|
|
|
MDL);
|
2001-02-12 19:40:05 +00:00
|
|
|
if (next)
|
2000-05-16 23:03:49 +00:00
|
|
|
interface_reference (&interfaces, next, MDL);
|
|
|
|
} else {
|
|
|
|
interface_dereference (&last -> next, MDL);
|
2001-02-12 19:40:05 +00:00
|
|
|
if (next)
|
|
|
|
interface_reference (&last -> next,
|
|
|
|
next, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
}
|
|
|
|
if (tmp -> next)
|
|
|
|
interface_dereference (&tmp -> next, MDL);
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/* Remember the interface in case we need to know
|
|
|
|
about it later. */
|
2000-05-16 23:03:49 +00:00
|
|
|
if (dummy_interfaces) {
|
|
|
|
interface_reference (&tmp -> next,
|
|
|
|
dummy_interfaces, MDL);
|
|
|
|
interface_dereference (&dummy_interfaces, MDL);
|
|
|
|
}
|
|
|
|
interface_reference (&dummy_interfaces, tmp, MDL);
|
|
|
|
interface_dereference (&tmp, MDL);
|
|
|
|
if (next)
|
|
|
|
interface_reference (&tmp, next, MDL);
|
1998-11-06 00:19:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
last = tmp;
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/* XXX: no ifp in Solaris */
|
|
|
|
/* memcpy (&foo, &tmp -> ifp -> ifr_addr,
|
|
|
|
sizeof tmp -> ifp -> ifr_addr);*/
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/* We must have a subnet declaration for each interface. */
|
2007-05-08 23:05:22 +00:00
|
|
|
if (!tmp->shared_network && (state == DISCOVER_SERVER)) {
|
|
|
|
log_error("%s", "");
|
|
|
|
if (local_family == AF_INET) {
|
|
|
|
log_error("No subnet declaration for %s (%s).",
|
|
|
|
tmp->name,
|
|
|
|
inet_ntoa(tmp->addresses[0]));
|
|
|
|
} else {
|
|
|
|
if (tmp->v6addresses != NULL) {
|
|
|
|
inet_ntop(AF_INET6,
|
|
|
|
&tmp->v6addresses[0],
|
|
|
|
abuf,
|
|
|
|
sizeof(abuf));
|
|
|
|
} else {
|
|
|
|
strcpy(abuf, "no addresses");
|
|
|
|
}
|
|
|
|
log_error("No subnet declaration for %s (%s).",
|
|
|
|
tmp->name,
|
|
|
|
abuf);
|
|
|
|
}
|
|
|
|
if (supports_multiple_interfaces(tmp)) {
|
2001-01-03 23:13:46 +00:00
|
|
|
log_error ("** Ignoring requests on %s. %s",
|
|
|
|
tmp -> name, "If this is not what");
|
|
|
|
log_error (" you want, please write %s",
|
|
|
|
"a subnet declaration");
|
|
|
|
log_error (" in your dhcpd.conf file %s",
|
|
|
|
"for the network segment");
|
|
|
|
log_error (" to %s %s %s",
|
2000-09-01 23:03:39 +00:00
|
|
|
"which interface",
|
2001-01-03 23:13:46 +00:00
|
|
|
tmp -> name, "is attached. **");
|
|
|
|
log_error ("%s", "");
|
2000-09-01 23:03:39 +00:00
|
|
|
goto next;
|
|
|
|
} else {
|
|
|
|
log_error ("You must write a subnet %s",
|
|
|
|
" declaration for this");
|
|
|
|
log_error ("subnet. You cannot prevent %s",
|
|
|
|
"the DHCP server");
|
|
|
|
log_error ("from listening on this subnet %s",
|
|
|
|
"because your");
|
|
|
|
log_fatal ("operating system does not %s.",
|
|
|
|
"support this capability");
|
|
|
|
}
|
1999-02-25 23:30:43 +00:00
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/* Find subnets that don't have valid interface
|
|
|
|
addresses... */
|
|
|
|
for (subnet = (tmp -> shared_network
|
|
|
|
? tmp -> shared_network -> subnets
|
|
|
|
: (struct subnet *)0);
|
|
|
|
subnet; subnet = subnet -> next_sibling) {
|
|
|
|
if (!subnet -> interface_address.len) {
|
|
|
|
/* Set the interface address for this subnet
|
|
|
|
to the first address we found. */
|
|
|
|
subnet -> interface_address.len = 4;
|
|
|
|
memcpy (subnet -> interface_address.iabuf,
|
2007-05-08 23:05:22 +00:00
|
|
|
&tmp->addresses[0].s_addr, 4);
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-12 19:40:05 +00:00
|
|
|
/* Flag the index as not having been set, so that the
|
|
|
|
interface registerer can set it or not as it chooses. */
|
|
|
|
tmp -> index = -1;
|
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
/* Register the interface... */
|
2007-05-08 23:05:22 +00:00
|
|
|
if (local_family == AF_INET) {
|
|
|
|
if_register_receive(tmp);
|
|
|
|
if_register_send(tmp);
|
|
|
|
} else {
|
|
|
|
if (state == DISCOVER_SERVER) {
|
|
|
|
if_register6(tmp, 1);
|
|
|
|
} else {
|
|
|
|
if_register6(tmp, 0);
|
|
|
|
}
|
|
|
|
}
|
2001-02-12 19:40:05 +00:00
|
|
|
|
|
|
|
interface_stash (tmp);
|
2000-09-04 22:27:41 +00:00
|
|
|
wifcount++;
|
2000-01-05 18:00:34 +00:00
|
|
|
#if defined (HAVE_SETFD)
|
|
|
|
if (fcntl (tmp -> rfdesc, F_SETFD, 1) < 0)
|
|
|
|
log_error ("Can't set close-on-exec on %s: %m",
|
|
|
|
tmp -> name);
|
|
|
|
if (tmp -> rfdesc != tmp -> wfdesc) {
|
|
|
|
if (fcntl (tmp -> wfdesc, F_SETFD, 1) < 0)
|
|
|
|
log_error ("Can't set close-on-exec on %s: %m",
|
|
|
|
tmp -> name);
|
|
|
|
}
|
|
|
|
#endif
|
2000-09-01 23:03:39 +00:00
|
|
|
next:
|
2000-05-16 23:03:49 +00:00
|
|
|
interface_dereference (&tmp, MDL);
|
|
|
|
if (next)
|
|
|
|
interface_reference (&tmp, next, MDL);
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Now register all the remaining interfaces as protocols. */
|
1999-09-08 01:44:08 +00:00
|
|
|
for (tmp = interfaces; tmp; tmp = tmp -> next) {
|
2000-01-28 20:30:37 +00:00
|
|
|
/* not if it's been registered before */
|
|
|
|
if (tmp -> flags & INTERFACE_RUNNING)
|
|
|
|
continue;
|
2000-10-10 22:31:41 +00:00
|
|
|
if (tmp -> rfdesc == -1)
|
|
|
|
continue;
|
2007-05-08 23:05:22 +00:00
|
|
|
if (local_family == AF_INET) {
|
|
|
|
status = omapi_register_io_object((omapi_object_t *)tmp,
|
|
|
|
if_readsocket,
|
|
|
|
0, got_one, 0, 0);
|
|
|
|
} else {
|
|
|
|
status = omapi_register_io_object((omapi_object_t *)tmp,
|
|
|
|
if_readsocket,
|
|
|
|
0, got_one_v6, 0, 0);
|
|
|
|
}
|
1999-09-08 01:44:08 +00:00
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
log_fatal ("Can't register I/O handle for %s: %s",
|
|
|
|
tmp -> name, isc_result_totext (status));
|
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2000-09-04 22:27:41 +00:00
|
|
|
if (state == DISCOVER_SERVER && wifcount == 0) {
|
|
|
|
log_info ("%s", "");
|
|
|
|
log_fatal ("Not configured to listen on any interfaces!");
|
|
|
|
}
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if ((local_family == AF_INET) && !setup_fallback) {
|
2000-02-15 20:40:36 +00:00
|
|
|
setup_fallback = 1;
|
2007-05-08 23:05:22 +00:00
|
|
|
maybe_setup_fallback();
|
2000-02-15 20:40:36 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 18:00:34 +00:00
|
|
|
#if defined (HAVE_SETFD)
|
|
|
|
if (fallback_interface) {
|
|
|
|
if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
|
|
|
|
log_error ("Can't set close-on-exec on fallback: %m");
|
|
|
|
if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
|
|
|
|
if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
|
|
|
|
log_error ("Can't set close-on-exec on fallback: %m");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
1999-02-14 19:04:05 +00:00
|
|
|
}
|
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
int if_readsocket (h)
|
|
|
|
omapi_object_t *h;
|
|
|
|
{
|
|
|
|
struct interface_info *ip;
|
|
|
|
|
|
|
|
if (h -> type != dhcp_type_interface)
|
2000-03-06 22:52:16 +00:00
|
|
|
return -1;
|
1999-09-08 01:44:08 +00:00
|
|
|
ip = (struct interface_info *)h;
|
|
|
|
return ip -> rfdesc;
|
|
|
|
}
|
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
int setup_fallback (struct interface_info **fp, const char *file, int line)
|
1999-02-14 19:04:05 +00:00
|
|
|
{
|
2000-05-16 23:03:49 +00:00
|
|
|
isc_result_t status;
|
|
|
|
|
|
|
|
status = interface_allocate (&fallback_interface, file, line);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
log_fatal ("Error allocating fallback interface: %s",
|
|
|
|
isc_result_totext (status));
|
1999-02-14 19:04:05 +00:00
|
|
|
strcpy (fallback_interface -> name, "fallback");
|
2000-05-16 23:03:49 +00:00
|
|
|
if (dhcp_interface_setup_hook)
|
|
|
|
(*dhcp_interface_setup_hook) (fallback_interface,
|
|
|
|
(struct iaddr *)0);
|
|
|
|
status = interface_reference (fp, fallback_interface, file, line);
|
2001-02-12 19:40:05 +00:00
|
|
|
|
2001-02-17 21:16:44 +00:00
|
|
|
fallback_interface -> index = -1;
|
2001-02-12 19:40:05 +00:00
|
|
|
interface_stash (fallback_interface);
|
2000-05-16 23:03:49 +00:00
|
|
|
return status == ISC_R_SUCCESS;
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void reinitialize_interfaces ()
|
|
|
|
{
|
|
|
|
struct interface_info *ip;
|
|
|
|
|
|
|
|
for (ip = interfaces; ip; ip = ip -> next) {
|
|
|
|
if_reinitialize_receive (ip);
|
|
|
|
if_reinitialize_send (ip);
|
|
|
|
}
|
|
|
|
|
1999-02-14 19:04:05 +00:00
|
|
|
if (fallback_interface)
|
|
|
|
if_reinitialize_send (fallback_interface);
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
interfaces_invalidated = 1;
|
|
|
|
}
|
1999-02-14 19:04:05 +00:00
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
isc_result_t got_one (h)
|
|
|
|
omapi_object_t *h;
|
1998-11-06 00:19:56 +00:00
|
|
|
{
|
|
|
|
struct sockaddr_in from;
|
|
|
|
struct hardware hfrom;
|
|
|
|
struct iaddr ifrom;
|
|
|
|
int result;
|
|
|
|
union {
|
|
|
|
unsigned char packbuf [4095]; /* Packet input buffer.
|
|
|
|
Must be as large as largest
|
|
|
|
possible MTU. */
|
|
|
|
struct dhcp_packet packet;
|
|
|
|
} u;
|
1999-09-08 01:44:08 +00:00
|
|
|
struct interface_info *ip;
|
|
|
|
|
|
|
|
if (h -> type != dhcp_type_interface)
|
|
|
|
return ISC_R_INVALIDARG;
|
|
|
|
ip = (struct interface_info *)h;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
again:
|
1998-11-06 00:19:56 +00:00
|
|
|
if ((result =
|
|
|
|
receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("receive_packet failed on %s: %m", ip -> name);
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_UNEXPECTED;
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
if (result == 0)
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_UNEXPECTED;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
1999-10-08 17:08:34 +00:00
|
|
|
/* If we didn't at least get the fixed portion of the BOOTP
|
|
|
|
packet, drop the packet. We're allowing packets with no
|
|
|
|
sname or filename, because we're aware of at least one
|
|
|
|
client that sends such packets, but this definitely falls
|
|
|
|
into the category of being forgiving. */
|
|
|
|
if (result < DHCP_FIXED_NON_UDP - DHCP_SNAME_LEN - DHCP_FILE_LEN)
|
|
|
|
return ISC_R_UNEXPECTED;
|
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
if (bootp_packet_handler) {
|
|
|
|
ifrom.len = 4;
|
|
|
|
memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
|
|
|
|
|
1999-10-07 06:36:35 +00:00
|
|
|
(*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
|
1998-11-06 00:19:56 +00:00
|
|
|
from.sin_port, ifrom, &hfrom);
|
|
|
|
}
|
2000-12-28 23:14:46 +00:00
|
|
|
|
|
|
|
/* If there is buffered data, read again. This is for, e.g.,
|
|
|
|
bpf, which may return two packets at once. */
|
|
|
|
if (ip -> rbuf_offset != ip -> rbuf_len)
|
|
|
|
goto again;
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
isc_result_t
|
|
|
|
got_one_v6(omapi_object_t *h) {
|
|
|
|
struct sockaddr_in6 from;
|
|
|
|
struct in6_addr to;
|
|
|
|
struct iaddr ifrom;
|
|
|
|
int result;
|
|
|
|
char buf[65536]; /* maximum size for a UDP packet is 65536 */
|
|
|
|
struct interface_info *ip;
|
|
|
|
int is_unicast;
|
|
|
|
|
|
|
|
if (h->type != dhcp_type_interface) {
|
|
|
|
return ISC_R_INVALIDARG;
|
|
|
|
}
|
|
|
|
ip = (struct interface_info *)h;
|
|
|
|
|
|
|
|
result = receive_packet6(ip, buf, sizeof(buf), &from, &to);
|
|
|
|
if (result < 0) {
|
|
|
|
log_error("receive_packet6() failed on %s: %m", ip->name);
|
|
|
|
return ISC_R_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dhcpv6_packet_handler != NULL) {
|
|
|
|
/*
|
|
|
|
* If a packet is not multicast, we assume it is unicast.
|
|
|
|
*/
|
|
|
|
if (IN6_IS_ADDR_MULTICAST(&to)) {
|
|
|
|
is_unicast = ISC_FALSE;
|
|
|
|
} else {
|
|
|
|
is_unicast = ISC_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifrom.len = 16;
|
|
|
|
memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len);
|
|
|
|
|
|
|
|
(*dhcpv6_packet_handler)(ip, buf,
|
|
|
|
result, from.sin6_port,
|
|
|
|
&ifrom, is_unicast);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t dhcp_interface_set_value (omapi_object_t *h,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_data_string_t *name,
|
|
|
|
omapi_typed_data_t *value)
|
1999-09-08 01:44:08 +00:00
|
|
|
{
|
2000-12-28 23:14:46 +00:00
|
|
|
struct interface_info *interface;
|
|
|
|
isc_result_t status;
|
|
|
|
int foo;
|
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
if (h -> type != dhcp_type_interface)
|
|
|
|
return ISC_R_INVALIDARG;
|
2000-12-28 23:14:46 +00:00
|
|
|
interface = (struct interface_info *)h;
|
|
|
|
|
|
|
|
if (!omapi_ds_strcmp (name, "name")) {
|
|
|
|
if ((value -> type == omapi_datatype_data ||
|
|
|
|
value -> type == omapi_datatype_string) &&
|
|
|
|
value -> u.buffer.len < sizeof interface -> name) {
|
|
|
|
memcpy (interface -> name,
|
|
|
|
value -> u.buffer.value,
|
|
|
|
value -> u.buffer.len);
|
|
|
|
interface -> name [value -> u.buffer.len] = 0;
|
|
|
|
} else
|
|
|
|
return ISC_R_INVALIDARG;
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to find some inner object that can take the value. */
|
|
|
|
if (h -> inner && h -> inner -> type -> set_value) {
|
|
|
|
status = ((*(h -> inner -> type -> set_value))
|
|
|
|
(h -> inner, id, name, value));
|
|
|
|
if (status == ISC_R_SUCCESS || status == ISC_R_UNCHANGED)
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
|
|
|
|
isc_result_t dhcp_interface_get_value (omapi_object_t *h,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_data_string_t *name,
|
|
|
|
omapi_value_t **value)
|
1999-09-08 01:44:08 +00:00
|
|
|
{
|
2000-12-28 23:14:46 +00:00
|
|
|
return ISC_R_NOTIMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t dhcp_interface_destroy (omapi_object_t *h,
|
|
|
|
const char *file, int line)
|
|
|
|
{
|
|
|
|
struct interface_info *interface;
|
|
|
|
isc_result_t status;
|
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
if (h -> type != dhcp_type_interface)
|
|
|
|
return ISC_R_INVALIDARG;
|
2000-12-28 23:14:46 +00:00
|
|
|
interface = (struct interface_info *)h;
|
|
|
|
|
2001-06-27 00:31:20 +00:00
|
|
|
if (interface -> ifp) {
|
2000-12-28 23:14:46 +00:00
|
|
|
dfree (interface -> ifp, file, line);
|
2001-06-27 00:31:20 +00:00
|
|
|
interface -> ifp = 0;
|
|
|
|
}
|
|
|
|
if (interface -> next)
|
|
|
|
interface_dereference (&interface -> next, file, line);
|
|
|
|
if (interface -> rbuf) {
|
|
|
|
dfree (interface -> rbuf, file, line);
|
|
|
|
interface -> rbuf = (unsigned char *)0;
|
|
|
|
}
|
|
|
|
if (interface -> client)
|
|
|
|
interface -> client = (struct client_state *)0;
|
|
|
|
|
|
|
|
if (interface -> shared_network)
|
|
|
|
omapi_object_dereference ((omapi_object_t **)
|
|
|
|
&interface -> shared_network, MDL);
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
return ISC_R_SUCCESS;
|
1999-09-08 01:44:08 +00:00
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
|
|
|
|
const char *name, va_list ap)
|
1999-09-08 01:44:08 +00:00
|
|
|
{
|
2000-12-28 23:14:46 +00:00
|
|
|
struct interface_info *ip, *interface;
|
|
|
|
struct client_config *config;
|
|
|
|
struct client_state *client;
|
|
|
|
isc_result_t status;
|
|
|
|
|
|
|
|
if (h -> type != dhcp_type_interface)
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_INVALIDARG;
|
2000-12-28 23:14:46 +00:00
|
|
|
interface = (struct interface_info *)h;
|
|
|
|
|
2001-04-05 20:50:19 +00:00
|
|
|
/* If it's an update signal, see if the interface is dead right
|
|
|
|
now, or isn't known at all, and if that's the case, revive it. */
|
|
|
|
if (!strcmp (name, "update")) {
|
|
|
|
for (ip = dummy_interfaces; ip; ip = ip -> next)
|
|
|
|
if (ip == interface)
|
|
|
|
break;
|
|
|
|
if (ip && dhcp_interface_startup_hook)
|
|
|
|
return (*dhcp_interface_startup_hook) (ip);
|
2000-12-28 23:14:46 +00:00
|
|
|
|
2001-04-05 20:50:19 +00:00
|
|
|
for (ip = interfaces; ip; ip = ip -> next)
|
|
|
|
if (ip == interface)
|
|
|
|
break;
|
|
|
|
if (!ip && dhcp_interface_startup_hook)
|
|
|
|
return (*dhcp_interface_startup_hook) (ip);
|
2000-12-28 23:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to find some inner object that can take the value. */
|
|
|
|
if (h -> inner && h -> inner -> type -> get_value) {
|
|
|
|
status = ((*(h -> inner -> type -> signal_handler))
|
|
|
|
(h -> inner, name, ap));
|
|
|
|
if (status == ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
}
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_object_t *h)
|
1999-09-08 01:44:08 +00:00
|
|
|
{
|
2000-12-28 23:14:46 +00:00
|
|
|
struct interface_info *interface;
|
|
|
|
isc_result_t status;
|
1999-09-08 01:44:08 +00:00
|
|
|
|
|
|
|
if (h -> type != dhcp_type_interface)
|
|
|
|
return ISC_R_INVALIDARG;
|
2000-12-28 23:14:46 +00:00
|
|
|
interface = (struct interface_info *)h;
|
|
|
|
|
|
|
|
/* Write out all the values. */
|
|
|
|
|
|
|
|
status = omapi_connection_put_name (c, "state");
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
2006-11-07 23:40:14 +00:00
|
|
|
if ((interface->flags & INTERFACE_REQUESTED) != 0)
|
2000-12-28 23:14:46 +00:00
|
|
|
status = omapi_connection_put_string (c, "up");
|
|
|
|
else
|
|
|
|
status = omapi_connection_put_string (c, "down");
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
/* Write out the inner object, if any. */
|
|
|
|
if (h -> inner && h -> inner -> type -> stuff_values) {
|
|
|
|
status = ((*(h -> inner -> type -> stuff_values))
|
|
|
|
(c, id, h -> inner));
|
|
|
|
if (status == ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_object_t *ref)
|
1999-09-08 01:44:08 +00:00
|
|
|
{
|
2000-12-28 23:14:46 +00:00
|
|
|
omapi_value_t *tv = (omapi_value_t *)0;
|
|
|
|
isc_result_t status;
|
|
|
|
struct interface_info *interface;
|
|
|
|
|
2001-06-27 00:31:20 +00:00
|
|
|
if (!ref)
|
|
|
|
return ISC_R_NOKEYS;
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
/* First see if we were sent a handle. */
|
|
|
|
status = omapi_get_value_str (ref, id, "handle", &tv);
|
|
|
|
if (status == ISC_R_SUCCESS) {
|
|
|
|
status = omapi_handle_td_lookup (ip, tv -> value);
|
|
|
|
|
|
|
|
omapi_value_dereference (&tv, MDL);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
/* Don't return the object if the type is wrong. */
|
|
|
|
if ((*ip) -> type != dhcp_type_interface) {
|
|
|
|
omapi_object_dereference (ip, MDL);
|
|
|
|
return ISC_R_INVALIDARG;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now look for an interface name. */
|
|
|
|
status = omapi_get_value_str (ref, id, "name", &tv);
|
|
|
|
if (status == ISC_R_SUCCESS) {
|
2001-04-05 20:50:19 +00:00
|
|
|
char *s;
|
|
|
|
unsigned len;
|
2000-12-28 23:14:46 +00:00
|
|
|
for (interface = interfaces; interface;
|
|
|
|
interface = interface -> next) {
|
2001-04-05 20:50:19 +00:00
|
|
|
s = memchr (interface -> name, 0, IFNAMSIZ);
|
|
|
|
if (s)
|
|
|
|
len = s - &interface -> name [0];
|
|
|
|
else
|
|
|
|
len = IFNAMSIZ;
|
|
|
|
if ((tv -> value -> u.buffer.len == len &&
|
|
|
|
!memcmp (interface -> name,
|
|
|
|
(char *)tv -> value -> u.buffer.value,
|
|
|
|
len)))
|
2000-12-28 23:14:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2001-04-05 20:50:19 +00:00
|
|
|
if (!interface) {
|
|
|
|
for (interface = dummy_interfaces;
|
|
|
|
interface; interface = interface -> next) {
|
|
|
|
s = memchr (interface -> name, 0, IFNAMSIZ);
|
|
|
|
if (s)
|
|
|
|
len = s - &interface -> name [0];
|
|
|
|
else
|
|
|
|
len = IFNAMSIZ;
|
|
|
|
if ((tv -> value -> u.buffer.len == len &&
|
|
|
|
!memcmp (interface -> name,
|
|
|
|
(char *)
|
|
|
|
tv -> value -> u.buffer.value,
|
|
|
|
len)))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
omapi_value_dereference (&tv, MDL);
|
|
|
|
if (*ip && *ip != (omapi_object_t *)interface) {
|
|
|
|
omapi_object_dereference (ip, MDL);
|
|
|
|
return ISC_R_KEYCONFLICT;
|
|
|
|
} else if (!interface) {
|
|
|
|
if (*ip)
|
|
|
|
omapi_object_dereference (ip, MDL);
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
} else if (!*ip)
|
|
|
|
omapi_object_reference (ip,
|
|
|
|
(omapi_object_t *)interface,
|
|
|
|
MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we get to here without finding an interface, no valid key was
|
|
|
|
specified. */
|
|
|
|
if (!*ip)
|
|
|
|
return ISC_R_NOKEYS;
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* actually just go discover the interface */
|
|
|
|
isc_result_t dhcp_interface_create (omapi_object_t **lp,
|
|
|
|
omapi_object_t *id)
|
|
|
|
{
|
|
|
|
struct interface_info *hp;
|
|
|
|
isc_result_t status;
|
1999-09-08 01:44:08 +00:00
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
hp = (struct interface_info *)0;
|
|
|
|
status = interface_allocate (&hp, MDL);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
hp -> flags = INTERFACE_REQUESTED;
|
|
|
|
status = interface_reference ((struct interface_info **)lp, hp, MDL);
|
|
|
|
interface_dereference (&hp, MDL);
|
|
|
|
return status;
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t dhcp_interface_remove (omapi_object_t *lp,
|
|
|
|
omapi_object_t *id)
|
|
|
|
{
|
|
|
|
struct interface_info *interface, *ip, *last;
|
|
|
|
|
|
|
|
interface = (struct interface_info *)lp;
|
|
|
|
|
|
|
|
/* remove from interfaces */
|
|
|
|
last = 0;
|
|
|
|
for (ip = interfaces; ip; ip = ip -> next) {
|
|
|
|
if (ip == interface) {
|
|
|
|
if (last) {
|
|
|
|
interface_dereference (&last -> next, MDL);
|
|
|
|
if (ip -> next)
|
|
|
|
interface_reference (&last -> next,
|
|
|
|
ip -> next, MDL);
|
|
|
|
} else {
|
|
|
|
interface_dereference (&interfaces, MDL);
|
|
|
|
if (ip -> next)
|
|
|
|
interface_reference (&interfaces,
|
|
|
|
ip -> next, MDL);
|
|
|
|
}
|
|
|
|
if (ip -> next)
|
|
|
|
interface_dereference (&ip -> next, MDL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
last = ip;
|
|
|
|
}
|
|
|
|
if (!ip)
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
|
|
|
|
/* add the interface to the dummy_interface list */
|
|
|
|
if (dummy_interfaces) {
|
|
|
|
interface_reference (&interface -> next,
|
|
|
|
dummy_interfaces, MDL);
|
|
|
|
interface_dereference (&dummy_interfaces, MDL);
|
|
|
|
}
|
|
|
|
interface_reference (&dummy_interfaces, interface, MDL);
|
|
|
|
|
|
|
|
/* do a DHCPRELEASE */
|
|
|
|
if (dhcp_interface_shutdown_hook)
|
|
|
|
(*dhcp_interface_shutdown_hook) (interface);
|
|
|
|
|
|
|
|
/* remove the io object */
|
|
|
|
omapi_unregister_io_object ((omapi_object_t *)interface);
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if (local_family == AF_INET) {
|
|
|
|
if_deregister_send(interface);
|
|
|
|
if_deregister_receive(interface);
|
|
|
|
} else {
|
|
|
|
if_deregister6(interface);
|
|
|
|
}
|
2000-12-28 23:14:46 +00:00
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2001-02-12 19:40:05 +00:00
|
|
|
|
|
|
|
void interface_stash (struct interface_info *tptr)
|
|
|
|
{
|
|
|
|
struct interface_info **vec;
|
|
|
|
int delta;
|
|
|
|
|
|
|
|
/* If the registerer didn't assign an index, assign one now. */
|
|
|
|
if (tptr -> index == -1) {
|
|
|
|
tptr -> index = interface_count++;
|
|
|
|
while (tptr -> index < interface_max &&
|
|
|
|
interface_vector [tptr -> index])
|
|
|
|
tptr -> index = interface_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (interface_max <= tptr -> index) {
|
|
|
|
delta = tptr -> index - interface_max + 10;
|
|
|
|
vec = dmalloc ((interface_max + delta) *
|
|
|
|
sizeof (struct interface_info *), MDL);
|
|
|
|
if (!vec)
|
|
|
|
return;
|
|
|
|
memset (&vec [interface_max], 0,
|
|
|
|
(sizeof (struct interface_info *)) * delta);
|
|
|
|
interface_max += delta;
|
|
|
|
if (interface_vector) {
|
|
|
|
memcpy (vec, interface_vector,
|
|
|
|
(interface_count *
|
|
|
|
sizeof (struct interface_info *)));
|
|
|
|
dfree (interface_vector, MDL);
|
|
|
|
}
|
|
|
|
interface_vector = vec;
|
|
|
|
}
|
2001-06-27 00:31:20 +00:00
|
|
|
interface_reference (&interface_vector [tptr -> index], tptr, MDL);
|
2001-02-12 19:40:05 +00:00
|
|
|
if (tptr -> index >= interface_count)
|
|
|
|
interface_count = tptr -> index + 1;
|
|
|
|
#if defined (TRACING)
|
|
|
|
trace_interface_register (interface_trace, tptr);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void interface_snorf (struct interface_info *tmp, int ir)
|
|
|
|
{
|
|
|
|
tmp -> circuit_id = (u_int8_t *)tmp -> name;
|
|
|
|
tmp -> circuit_id_len = strlen (tmp -> name);
|
|
|
|
tmp -> remote_id = 0;
|
|
|
|
tmp -> remote_id_len = 0;
|
|
|
|
tmp -> flags = ir;
|
|
|
|
if (interfaces) {
|
|
|
|
interface_reference (&tmp -> next,
|
|
|
|
interfaces, MDL);
|
|
|
|
interface_dereference (&interfaces, MDL);
|
|
|
|
}
|
|
|
|
interface_reference (&interfaces, tmp, MDL);
|
|
|
|
}
|