File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / dhcp / common / discover.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Oct 9 09:06:54 2012 UTC (11 years, 8 months ago) by misho
Branches: dhcp, MAIN
CVS tags: v4_1_R7p0, v4_1_R7, v4_1_R4, HEAD
dhcp 4.1 r7

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>