10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52157Sdh155122  * Common Development and Distribution License (the "License").
62157Sdh155122  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
222157Sdh155122  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #include <sys/socket.h>
300Sstevel@tonic-gate #include <net/if.h>
310Sstevel@tonic-gate #include <sys/dlpi.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <sys/sockio.h>
340Sstevel@tonic-gate #include <netinet/in.h>
350Sstevel@tonic-gate #include <netinet/dhcp.h>
360Sstevel@tonic-gate #include <string.h>
370Sstevel@tonic-gate #include <unistd.h>
380Sstevel@tonic-gate #include <netinet/if_ether.h>
390Sstevel@tonic-gate #include <signal.h>
400Sstevel@tonic-gate #include <dhcpmsg.h>
410Sstevel@tonic-gate #include <libdevinfo.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include "interface.h"
440Sstevel@tonic-gate #include "util.h"
450Sstevel@tonic-gate #include "dlpi_io.h"
460Sstevel@tonic-gate #include "packet.h"
470Sstevel@tonic-gate #include "defaults.h"
480Sstevel@tonic-gate #include "states.h"
490Sstevel@tonic-gate #include "script_handler.h"
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate  * note to the reader:
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  * the terminology in here is slightly confusing.  in particular, the
550Sstevel@tonic-gate  * term `ifslist' is used to refer both to the `struct ifslist' entry
560Sstevel@tonic-gate  * that makes up a specific interface entry, and the `internal
570Sstevel@tonic-gate  * ifslist' which is a linked list of struct ifslists.  to reduce
580Sstevel@tonic-gate  * confusion, in the comments, a `struct ifslist' is referred to as
590Sstevel@tonic-gate  * an `ifs', and `ifslist' refers to the internal ifslist.
600Sstevel@tonic-gate  *
610Sstevel@tonic-gate  */
620Sstevel@tonic-gate 
630Sstevel@tonic-gate static struct ifslist	*ifsheadp;
640Sstevel@tonic-gate static unsigned int	ifscount;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate static void	init_ifs(struct ifslist *);
670Sstevel@tonic-gate static void	free_ifs(struct ifslist *);
680Sstevel@tonic-gate static void	cancel_ifs_timer(struct ifslist *, int);
690Sstevel@tonic-gate 
700Sstevel@tonic-gate static boolean_t	get_prom_prop(const char *, const char *, uchar_t **,
710Sstevel@tonic-gate 			    unsigned int *);
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate  * insert_ifs(): creates a new ifs and chains it on the ifslist.  initializes
750Sstevel@tonic-gate  *		 state which remains consistent across all use of the ifs entry
760Sstevel@tonic-gate  *
770Sstevel@tonic-gate  *   input: const char *: the name of the ifs entry (interface name)
780Sstevel@tonic-gate  *	    boolean_t: if B_TRUE, we're adopting the interface
790Sstevel@tonic-gate  *	    int *: ignored on input; if insert_ifs fails, set to a DHCP_IPC_E_*
800Sstevel@tonic-gate  *		   error code with the reason why
810Sstevel@tonic-gate  *  output: struct ifslist *: a pointer to the new ifs entry, or NULL on failure
820Sstevel@tonic-gate  */
830Sstevel@tonic-gate 
840Sstevel@tonic-gate struct ifslist *
850Sstevel@tonic-gate insert_ifs(const char *if_name, boolean_t is_adopting, int *error)
860Sstevel@tonic-gate {
870Sstevel@tonic-gate 	uint32_t		buf[DLPI_BUF_MAX / sizeof (uint32_t)];
880Sstevel@tonic-gate 	dl_info_ack_t		*dlia = (dl_info_ack_t *)buf;
890Sstevel@tonic-gate 	caddr_t			dl_addr;
900Sstevel@tonic-gate 	struct ifreq    	ifr;
910Sstevel@tonic-gate 	unsigned int		i, client_id_len = 0;
920Sstevel@tonic-gate 	uchar_t			*client_id = NULL;
930Sstevel@tonic-gate 	const char		*prl;
940Sstevel@tonic-gate 	struct ifslist		*ifsp;
950Sstevel@tonic-gate 	long			seed;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate 	ifsp = lookup_ifs(if_name);
980Sstevel@tonic-gate 	if (ifsp != NULL) {
990Sstevel@tonic-gate 		*error = DHCP_IPC_E_INT;	/* should never happen */
1000Sstevel@tonic-gate 		return (NULL);
1010Sstevel@tonic-gate 	}
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	/*
1040Sstevel@tonic-gate 	 * okay, we've got a request to put a new interface under our
1050Sstevel@tonic-gate 	 * control.  it's our job to set everything that doesn't
1060Sstevel@tonic-gate 	 * change for the life of the interface.  (state that changes
1070Sstevel@tonic-gate 	 * should be initialized in init_ifs() and reset by reset_ifs())
1080Sstevel@tonic-gate 	 *
1090Sstevel@tonic-gate 	 *  1. verify the interface can support DHCP
1100Sstevel@tonic-gate 	 *  2. get the interface mtu
1110Sstevel@tonic-gate 	 *  3. get the interface hardware type and hardware length
1120Sstevel@tonic-gate 	 *  4. get the interface hardware address
1130Sstevel@tonic-gate 	 *  5. get the interface broadcast address
1140Sstevel@tonic-gate 	 *  6. get the interface flags
1150Sstevel@tonic-gate 	 */
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	ifsp = calloc(1, sizeof (struct ifslist));
1180Sstevel@tonic-gate 	if (ifsp == NULL) {
1190Sstevel@tonic-gate 		dhcpmsg(MSG_ERR, "insert_ifs: cannot allocate ifs entry for "
1200Sstevel@tonic-gate 		    "%s", if_name);
1210Sstevel@tonic-gate 		*error = DHCP_IPC_E_MEMORY;
1220Sstevel@tonic-gate 		return (NULL);
1230Sstevel@tonic-gate 	}
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	(void) strlcpy(ifsp->if_name, if_name, IFNAMSIZ);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	/* step 1 */
1280Sstevel@tonic-gate 	ifsp->if_dlpi_fd = dlpi_open(if_name, dlia, sizeof (buf), ETHERTYPE_IP);
1290Sstevel@tonic-gate 	if (ifsp->if_dlpi_fd == -1) {
1300Sstevel@tonic-gate 		*error = DHCP_IPC_E_INVIF;
1310Sstevel@tonic-gate 		goto failure;
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	init_ifs(ifsp);			/* ifsp->if_dlpi_fd must be valid */
1350Sstevel@tonic-gate 	ipc_action_init(ifsp);
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	/* step 2 */
1380Sstevel@tonic-gate 	ifsp->if_max = dlia->dl_max_sdu;
1390Sstevel@tonic-gate 	ifsp->if_opt = ifsp->if_max - BASE_PKT_SIZE;
1400Sstevel@tonic-gate 	ifsp->if_min = dlia->dl_min_sdu;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	if (ifsp->if_max < DHCP_DEF_MAX_SIZE) {
1430Sstevel@tonic-gate 		dhcpmsg(MSG_ERROR, "insert_ifs: %s does not have a large "
1440Sstevel@tonic-gate 		    "enough maximum SDU to support DHCP", if_name);
1450Sstevel@tonic-gate 		*error = DHCP_IPC_E_INVIF;
1460Sstevel@tonic-gate 		goto failure;
1470Sstevel@tonic-gate 	}
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	/* step 3 */
1500Sstevel@tonic-gate 	ifsp->if_hwtype = dlpi_to_arp(dlia->dl_mac_type);
1510Sstevel@tonic-gate 	ifsp->if_hwlen  = dlia->dl_addr_length - abs(dlia->dl_sap_length);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	dhcpmsg(MSG_DEBUG, "insert_ifs: %s: sdumax %d, optmax %d, hwtype %d, "
1540Sstevel@tonic-gate 	    "hwlen %d", if_name, ifsp->if_max, ifsp->if_opt, ifsp->if_hwtype,
1550Sstevel@tonic-gate 	    ifsp->if_hwlen);
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	/* step 4 */
1580Sstevel@tonic-gate 	ifsp->if_hwaddr = malloc(ifsp->if_hwlen);
1590Sstevel@tonic-gate 	if (ifsp->if_hwaddr == NULL) {
1600Sstevel@tonic-gate 		dhcpmsg(MSG_ERR, "insert_ifs: cannot allocate if_hwaddr "
1610Sstevel@tonic-gate 		    "for %s", if_name);
1620Sstevel@tonic-gate 		*error = DHCP_IPC_E_MEMORY;
1630Sstevel@tonic-gate 		goto failure;
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	/*
1670Sstevel@tonic-gate 	 * depending on the DLPI device, the sap and hardware addresses
1680Sstevel@tonic-gate 	 * can be in either order within the dlsap address; find the
1690Sstevel@tonic-gate 	 * location of the hardware address using dl_sap_length.  see the
1700Sstevel@tonic-gate 	 * DLPI specification for more on this braindamage.
1710Sstevel@tonic-gate 	 */
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	dl_addr = (caddr_t)dlia + dlia->dl_addr_offset;
1740Sstevel@tonic-gate 	if (dlia->dl_sap_length > 0) {
1750Sstevel@tonic-gate 		ifsp->if_sap_before++;
1760Sstevel@tonic-gate 		dl_addr += dlia->dl_sap_length;
1770Sstevel@tonic-gate 	}
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	(void) memcpy(ifsp->if_hwaddr, dl_addr, ifsp->if_hwlen);
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	/* step 5 */
1820Sstevel@tonic-gate 	ifsp->if_saplen = abs(dlia->dl_sap_length);
1830Sstevel@tonic-gate 	ifsp->if_daddr  = build_broadcast_dest(dlia, &ifsp->if_dlen);
1840Sstevel@tonic-gate 	if (ifsp->if_daddr == NULL) {
1850Sstevel@tonic-gate 		dhcpmsg(MSG_ERR, "insert_ifs: cannot allocate if_daddr "
1860Sstevel@tonic-gate 		    "for %s", if_name);
1870Sstevel@tonic-gate 		*error = DHCP_IPC_E_MEMORY;
1880Sstevel@tonic-gate 		goto failure;
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	/* step 6 */
1920Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
1930Sstevel@tonic-gate 
194*2546Scarlsonj 	if (ioctl(ifsp->if_sock_fd, SIOCGIFINDEX, &ifr) == -1) {
195*2546Scarlsonj 		if (errno == ENXIO)
196*2546Scarlsonj 			*error = DHCP_IPC_E_INVIF;
197*2546Scarlsonj 		else
198*2546Scarlsonj 			*error = DHCP_IPC_E_INT;
199*2546Scarlsonj 		dhcpmsg(MSG_ERR, "insert_ifs: SIOCGIFINDEX for %s", if_name);
200*2546Scarlsonj 		goto failure;
201*2546Scarlsonj 	}
202*2546Scarlsonj 	ifsp->if_index = ifr.ifr_index;
203*2546Scarlsonj 
2040Sstevel@tonic-gate 	if (ioctl(ifsp->if_sock_fd, SIOCGIFFLAGS, &ifr) == -1) {
2050Sstevel@tonic-gate 		if (errno == ENXIO)
2060Sstevel@tonic-gate 			*error = DHCP_IPC_E_INVIF;
2070Sstevel@tonic-gate 		else
2080Sstevel@tonic-gate 			*error = DHCP_IPC_E_INT;
2090Sstevel@tonic-gate 		dhcpmsg(MSG_ERR, "insert_ifs: SIOCGIFFLAGS for %s", if_name);
2100Sstevel@tonic-gate 		goto failure;
2110Sstevel@tonic-gate 	}
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	/*
2140Sstevel@tonic-gate 	 * if DHCPRUNNING is already set on the interface and we're
2150Sstevel@tonic-gate 	 * not adopting it, the agent probably crashed and burned.
2160Sstevel@tonic-gate 	 * note it, but don't let it stop the proceedings.  we're
2170Sstevel@tonic-gate 	 * pretty sure we're not already running, since we wouldn't
2180Sstevel@tonic-gate 	 * have been able to bind to our IPC port.
2190Sstevel@tonic-gate 	 */
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	if ((is_adopting == B_FALSE) && (ifr.ifr_flags & IFF_DHCPRUNNING))
2220Sstevel@tonic-gate 		dhcpmsg(MSG_WARNING, "insert_ifs: DHCP flag already set on %s",
2230Sstevel@tonic-gate 		    if_name);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	ifr.ifr_flags |= IFF_DHCPRUNNING;
2260Sstevel@tonic-gate 	(void) ioctl(ifsp->if_sock_fd, SIOCSIFFLAGS, &ifr);
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	ifsp->if_send_pkt.pkt = calloc(ifsp->if_max, 1);
2290Sstevel@tonic-gate 	if (ifsp->if_send_pkt.pkt == NULL) {
2300Sstevel@tonic-gate 		dhcpmsg(MSG_ERR, "insert_ifs: cannot allocate if_send_pkt "
2310Sstevel@tonic-gate 		    "for %s", if_name);
2320Sstevel@tonic-gate 		*error = DHCP_IPC_E_MEMORY;
2330Sstevel@tonic-gate 		goto failure;
2340Sstevel@tonic-gate 	}
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	if (is_adopting) {
2370Sstevel@tonic-gate 		/*
2380Sstevel@tonic-gate 		 * if the agent is adopting a lease OBP is initially
2390Sstevel@tonic-gate 		 * searched for a client-id
2400Sstevel@tonic-gate 		 */
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		dhcpmsg(MSG_DEBUG, "insert_ifs: getting /chosen:clientid "
2430Sstevel@tonic-gate 		    "property");
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 		if (!get_prom_prop("chosen", "client-id", &ifsp->if_cid,
2460Sstevel@tonic-gate 		    &client_id_len)) {
2470Sstevel@tonic-gate 			/*
2480Sstevel@tonic-gate 			 * a failure occurred trying to acquire the client-id
2490Sstevel@tonic-gate 			 */
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 			dhcpmsg(MSG_DEBUG, "insert_ifs: cannot allocate client "
2520Sstevel@tonic-gate 			    "id for %s", if_name);
2530Sstevel@tonic-gate 			*error = DHCP_IPC_E_INT;
2540Sstevel@tonic-gate 			goto failure;
2550Sstevel@tonic-gate 		} else if (dlia->dl_mac_type == DL_IB && ifsp->if_cid == NULL) {
2560Sstevel@tonic-gate 			/*
2570Sstevel@tonic-gate 			 * when the interface is infiniband and the agent
2580Sstevel@tonic-gate 			 * is adopting the lease there must be an OBP
2590Sstevel@tonic-gate 			 * client-id.
2600Sstevel@tonic-gate 			 */
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 			dhcpmsg(MSG_DEBUG, "insert_ifs: no /chosen:clientid"
2630Sstevel@tonic-gate 			    "id for %s", if_name);
2640Sstevel@tonic-gate 			*error = DHCP_IPC_E_INT;
2650Sstevel@tonic-gate 			goto failure;
2660Sstevel@tonic-gate 		}
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 		ifsp->if_cidlen = client_id_len;
2690Sstevel@tonic-gate 	} else {
2700Sstevel@tonic-gate 		/*
2710Sstevel@tonic-gate 		 * look in defaults file for the client-id
2720Sstevel@tonic-gate 		 */
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 		dhcpmsg(MSG_DEBUG, "insert_ifs: getting defaults client-id "
2750Sstevel@tonic-gate 		    "property");
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 		client_id = df_get_octet(if_name, DF_CLIENT_ID, &client_id_len);
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 		/*
2800Sstevel@tonic-gate 		 * at this point, all logical interfaces must be explicitly
2810Sstevel@tonic-gate 		 * configured with a client id by the administrator.
2820Sstevel@tonic-gate 		 */
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 		if (client_id == NULL && strchr(if_name, ':') != NULL) {
2850Sstevel@tonic-gate 			dhcpmsg(MSG_ERROR, "no client id configured for "
2860Sstevel@tonic-gate 			    "logical interface %s; cannot manage", if_name);
2870Sstevel@tonic-gate 			*error = DHCP_IPC_E_NOIFCID;
2880Sstevel@tonic-gate 			goto failure;
2890Sstevel@tonic-gate 		}
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		if (client_id != NULL) {
2920Sstevel@tonic-gate 			/*
2930Sstevel@tonic-gate 			 * the defaults client-id value must be copied out to
2940Sstevel@tonic-gate 			 * another buffer
2950Sstevel@tonic-gate 			 */
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 			ifsp->if_cid = calloc(client_id_len, sizeof (uchar_t));
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 			if (ifsp->if_cid == NULL) {
3000Sstevel@tonic-gate 				dhcpmsg(MSG_ERR, "insert_ifs: cannot "
3010Sstevel@tonic-gate 				    "allocate client id for %s", if_name);
3020Sstevel@tonic-gate 				*error = DHCP_IPC_E_MEMORY;
3030Sstevel@tonic-gate 				goto failure;
3040Sstevel@tonic-gate 			}
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 			(void) memcpy(ifsp->if_cid, client_id, client_id_len);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 			ifsp->if_cidlen = client_id_len;
3090Sstevel@tonic-gate 		} else if (dlia->dl_mac_type == DL_IB) {
3100Sstevel@tonic-gate 			/*
3110Sstevel@tonic-gate 			 * This comes from DHCP over IPoIB spec. In the absence
3120Sstevel@tonic-gate 			 * of an user specified client id, IPoIB automatically
3130Sstevel@tonic-gate 			 * uses the required format, with the unique 4 octet
3140Sstevel@tonic-gate 			 * value set to 0 (since IPoIB driver allows only a
3150Sstevel@tonic-gate 			 * single interface on a port with a specific GID to
3160Sstevel@tonic-gate 			 * belong to an IP subnet (PSARC 2001/289,
3170Sstevel@tonic-gate 			 * FWARC 2002/702).
3180Sstevel@tonic-gate 			 *
3190Sstevel@tonic-gate 			 *   Type  Client-Identifier
3200Sstevel@tonic-gate 			 * +-----+-----+-----+-----+-----+----....----+
3210Sstevel@tonic-gate 			 * |  0  |  0 (4 octets)   |   GID (16 octets)|
3220Sstevel@tonic-gate 			 * +-----+-----+-----+-----+-----+----....----+
3230Sstevel@tonic-gate 			 */
3240Sstevel@tonic-gate 			ifsp->if_cidlen = 1 + 4 + 16;
3250Sstevel@tonic-gate 			ifsp->if_cid = client_id = malloc(ifsp->if_cidlen);
3260Sstevel@tonic-gate 			if (ifsp->if_cid == NULL) {
3270Sstevel@tonic-gate 				dhcpmsg(MSG_ERR, "insert_ifs: cannot "
3280Sstevel@tonic-gate 				    "allocate client id for %s", if_name);
3290Sstevel@tonic-gate 				*error = DHCP_IPC_E_MEMORY;
3300Sstevel@tonic-gate 				goto failure;
3310Sstevel@tonic-gate 			}
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 			/*
3340Sstevel@tonic-gate 			 * Pick the GID from the mac address. The format
3350Sstevel@tonic-gate 			 * of the hardware address is:
3360Sstevel@tonic-gate 			 * +-----+-----+-----+-----+----....----+
3370Sstevel@tonic-gate 			 * | QPN (4 octets)  |   GID (16 octets)|
3380Sstevel@tonic-gate 			 * +-----+-----+-----+-----+----....----+
3390Sstevel@tonic-gate 			 */
3400Sstevel@tonic-gate 			(void) memcpy(client_id + 5, ifsp->if_hwaddr + 4,
3410Sstevel@tonic-gate 			    ifsp->if_hwlen - 4);
3420Sstevel@tonic-gate 			(void) memset(client_id, 0, 5);
3430Sstevel@tonic-gate 		}
3440Sstevel@tonic-gate 	}
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	/*
3470Sstevel@tonic-gate 	 * initialize the parameter request list, if there is one.
3480Sstevel@tonic-gate 	 */
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	prl = df_get_string(if_name, DF_PARAM_REQUEST_LIST);
3510Sstevel@tonic-gate 	if (prl == NULL)
3520Sstevel@tonic-gate 		ifsp->if_prl = NULL;
3530Sstevel@tonic-gate 	else {
3540Sstevel@tonic-gate 		for (ifsp->if_prllen = 1, i = 0; prl[i] != '\0'; i++)
3550Sstevel@tonic-gate 			if (prl[i] == ',')
3560Sstevel@tonic-gate 				ifsp->if_prllen++;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 		ifsp->if_prl = malloc(ifsp->if_prllen);
3590Sstevel@tonic-gate 		if (ifsp->if_prl == NULL) {
3600Sstevel@tonic-gate 			dhcpmsg(MSG_WARNING, "insert_ifs: cannot allocate "
3610Sstevel@tonic-gate 			    "parameter request list for %s (continuing)",
3620Sstevel@tonic-gate 			    if_name);
3630Sstevel@tonic-gate 		} else {
3640Sstevel@tonic-gate 			for (i = 0; i < ifsp->if_prllen; prl++, i++) {
3650Sstevel@tonic-gate 				ifsp->if_prl[i] = strtoul(prl, NULL, 0);
3660Sstevel@tonic-gate 				while (*prl != ',' && *prl != '\0')
3670Sstevel@tonic-gate 					prl++;
3680Sstevel@tonic-gate 				if (*prl == '\0')
3690Sstevel@tonic-gate 					break;
3700Sstevel@tonic-gate 			}
3710Sstevel@tonic-gate 		}
3720Sstevel@tonic-gate 	}
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	ifsp->if_offer_wait = df_get_int(if_name, DF_OFFER_WAIT);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	/*
3770Sstevel@tonic-gate 	 * we're past the point of failure; chain it on.
3780Sstevel@tonic-gate 	 */
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 	ifsp->next	= ifsheadp;
3810Sstevel@tonic-gate 	ifsp->prev	= NULL;
3820Sstevel@tonic-gate 	ifsheadp	= ifsp;
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	if (ifsheadp->next != NULL)
3850Sstevel@tonic-gate 		ifsheadp->next->prev = ifsheadp;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	hold_ifs(ifsp);
3880Sstevel@tonic-gate 	ifscount++;
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 	if (inactivity_id != -1) {
3910Sstevel@tonic-gate 		if (iu_cancel_timer(tq, inactivity_id, NULL) == 1)
3920Sstevel@tonic-gate 			inactivity_id = -1;
3930Sstevel@tonic-gate 	}
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	/*
3960Sstevel@tonic-gate 	 * seed the random number generator, since we're going to need it
3970Sstevel@tonic-gate 	 * to set transaction id's and for exponential backoff.  if an
3980Sstevel@tonic-gate 	 * interface is already initialized, then we just end up harmlessly
3990Sstevel@tonic-gate 	 * reseeding it.  note that we try to spread the hardware address
4000Sstevel@tonic-gate 	 * over as many bits of the seed as possible.
4010Sstevel@tonic-gate 	 */
4020Sstevel@tonic-gate 	seed = gethrtime();
4030Sstevel@tonic-gate 	for (i = 0; i < ifsp->if_hwlen; i++)
4040Sstevel@tonic-gate 		seed += ifsp->if_hwaddr[i] << ((i % 7) * 4);
4050Sstevel@tonic-gate 	seed ^= getpid();
4060Sstevel@tonic-gate 	srand48(seed);
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 	dhcpmsg(MSG_DEBUG, "insert_ifs: inserted interface %s", if_name);
4090Sstevel@tonic-gate 	return (ifsp);
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate failure:
4120Sstevel@tonic-gate 	free_ifs(ifsp);
4130Sstevel@tonic-gate 	return (NULL);
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate /*
4170Sstevel@tonic-gate  * init_ifs(): puts an ifs in its initial state
4180Sstevel@tonic-gate  *
4190Sstevel@tonic-gate  *   input: struct ifslist *: the ifs to initialize
4200Sstevel@tonic-gate  *  output: void
4210Sstevel@tonic-gate  *    note: if the interface isn't fresh, use reset_ifs()
4220Sstevel@tonic-gate  */
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate static void
4250Sstevel@tonic-gate init_ifs(struct ifslist *ifsp)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	/*
4280Sstevel@tonic-gate 	 * if_sock_ip_fd is created and bound in configure_if().
4290Sstevel@tonic-gate 	 * if_sock_fd is bound in configure_if(); see comments in
4300Sstevel@tonic-gate 	 * bound.c for more details on why.  if creation of if_sock_fd
4310Sstevel@tonic-gate 	 * fails, we'll need more context anyway, so don't check.
4320Sstevel@tonic-gate 	 */
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	ifsp->if_sock_fd	= socket(AF_INET, SOCK_DGRAM, 0);
4350Sstevel@tonic-gate 	ifsp->if_sock_ip_fd	= -1;
4360Sstevel@tonic-gate 	ifsp->if_state		= INIT;
4370Sstevel@tonic-gate 	ifsp->if_routers	= NULL;
4380Sstevel@tonic-gate 	ifsp->if_nrouters	= 0;
4390Sstevel@tonic-gate 	ifsp->if_ack		= NULL;
4400Sstevel@tonic-gate 	ifsp->if_orig_ack	= NULL;
4410Sstevel@tonic-gate 	ifsp->if_server.s_addr  = htonl(INADDR_BROADCAST);
4420Sstevel@tonic-gate 	ifsp->if_neg_monosec 	= monosec();
4430Sstevel@tonic-gate 	ifsp->if_lease 		= 0;
4440Sstevel@tonic-gate 	ifsp->if_t1 		= 0;
4450Sstevel@tonic-gate 	ifsp->if_t2 		= 0;
4460Sstevel@tonic-gate 	ifsp->if_reqhost	= NULL;
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 	ifsp->if_script_helper_pid	= -1;
4490Sstevel@tonic-gate 	ifsp->if_script_callback	= NULL;
4500Sstevel@tonic-gate 	ifsp->if_script_event		= NULL;
4510Sstevel@tonic-gate 	ifsp->if_callback_msg		= NULL;
4520Sstevel@tonic-gate 	ifsp->if_script_event_id	= -1;
4530Sstevel@tonic-gate 	ifsp->if_script_pid		= -1;
4540Sstevel@tonic-gate 	ifsp->if_script_fd		= -1;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	ifsp->if_offer_id		= -1;
4570Sstevel@tonic-gate 	ifsp->if_acknak_id		= -1;
4580Sstevel@tonic-gate 	ifsp->if_acknak_bcast_id	= -1;
4590Sstevel@tonic-gate 	ifsp->if_timer[DHCP_T1_TIMER]	= -1;
4600Sstevel@tonic-gate 	ifsp->if_timer[DHCP_T2_TIMER]   = -1;
4610Sstevel@tonic-gate 	ifsp->if_timer[DHCP_LEASE_TIMER] = -1;
4622157Sdh155122 	ifsp->if_offer_timer		= -1;
4630Sstevel@tonic-gate 
4640Sstevel@tonic-gate 	set_packet_filter(ifsp->if_dlpi_fd, dhcp_filter, NULL, "DHCP");
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	dhcpmsg(MSG_DEBUG, "init_ifs: initted interface %s", ifsp->if_name);
4670Sstevel@tonic-gate }
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate /*
4700Sstevel@tonic-gate  * remove_ifs_default_routes(): removes an ifs's default routes
4710Sstevel@tonic-gate  *
4720Sstevel@tonic-gate  *   input: struct ifslist *: the ifs whose default routes need to be removed
4730Sstevel@tonic-gate  *  output: void
4740Sstevel@tonic-gate  */
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate static void
4770Sstevel@tonic-gate remove_ifs_default_routes(struct ifslist *ifsp)
4780Sstevel@tonic-gate {
4790Sstevel@tonic-gate 	if (ifsp->if_routers != NULL) {
4800Sstevel@tonic-gate 		while (ifsp->if_nrouters > 0) {
4810Sstevel@tonic-gate 			(void) del_default_route(ifsp->if_name,
4820Sstevel@tonic-gate 			    &ifsp->if_routers[--ifsp->if_nrouters]);
4830Sstevel@tonic-gate 		}
4840Sstevel@tonic-gate 		free(ifsp->if_routers);
4850Sstevel@tonic-gate 		ifsp->if_routers = NULL;
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate /*
4900Sstevel@tonic-gate  * reset_ifs(): resets an ifs to its initial state
4910Sstevel@tonic-gate  *
4920Sstevel@tonic-gate  *   input: struct ifslist *: the ifs to reset
4930Sstevel@tonic-gate  *  output: void
4940Sstevel@tonic-gate  */
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate void
4970Sstevel@tonic-gate reset_ifs(struct ifslist *ifsp)
4980Sstevel@tonic-gate {
4990Sstevel@tonic-gate 	ifsp->if_dflags &= ~DHCP_IF_FAILED;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	remove_ifs_default_routes(ifsp);
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate 	if (ifsp->if_sock_fd != -1)
5040Sstevel@tonic-gate 		(void) close(ifsp->if_sock_fd);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	if (ifsp->if_orig_ack != ifsp->if_ack)
5070Sstevel@tonic-gate 		free_pkt_list(&ifsp->if_orig_ack);
5080Sstevel@tonic-gate 
5090Sstevel@tonic-gate 	free_pkt_list(&ifsp->if_ack);
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	if (ifsp->if_sock_ip_fd != -1)
5120Sstevel@tonic-gate 		(void) close(ifsp->if_sock_ip_fd);
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	if (ifsp->if_offer_id != -1) {
5150Sstevel@tonic-gate 		if (iu_unregister_event(eh, ifsp->if_offer_id, NULL) != 0)
5160Sstevel@tonic-gate 			(void) release_ifs(ifsp);
5170Sstevel@tonic-gate 	}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	(void) unregister_acknak(ifsp);		/* just in case */
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	cancel_ifs_timers(ifsp);
5222157Sdh155122 
5232157Sdh155122 	if (ifsp->if_offer_timer != -1) {
5242157Sdh155122 		if (iu_cancel_timer(tq, ifsp->if_offer_timer, NULL))
5252157Sdh155122 			(void) release_ifs(ifsp);
5262157Sdh155122 	}
5272157Sdh155122 
5282157Sdh155122 	stop_pkt_retransmission(ifsp);
5292157Sdh155122 
5300Sstevel@tonic-gate 	init_ifs(ifsp);
5310Sstevel@tonic-gate }
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate /*
5340Sstevel@tonic-gate  * lookup_ifs(): looks up an ifs, given its name
5350Sstevel@tonic-gate  *
5360Sstevel@tonic-gate  *   input: const char *: the name of the ifs entry (the interface name)
5370Sstevel@tonic-gate  *			  the name "" searches for the primary interface
5380Sstevel@tonic-gate  *  output: struct ifslist *: the corresponding ifs, or NULL if not found
5390Sstevel@tonic-gate  */
5400Sstevel@tonic-gate 
5410Sstevel@tonic-gate struct ifslist *
5420Sstevel@tonic-gate lookup_ifs(const char *if_name)
5430Sstevel@tonic-gate {
5440Sstevel@tonic-gate 	struct ifslist	*ifs;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	for (ifs = ifsheadp; ifs != NULL; ifs = ifs->next)
5470Sstevel@tonic-gate 		if (*if_name != '\0') {
5480Sstevel@tonic-gate 			if (strcmp(ifs->if_name, if_name) == 0)
5490Sstevel@tonic-gate 				break;
5500Sstevel@tonic-gate 		} else if (ifs->if_dflags & DHCP_IF_PRIMARY)
5510Sstevel@tonic-gate 			break;
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	return (ifs);
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate /*
5570Sstevel@tonic-gate  * lookup_ifs_by_xid(): looks up an ifs, given its last used transaction id
5580Sstevel@tonic-gate  *
5590Sstevel@tonic-gate  *   input: int: the transaction id to look up
5600Sstevel@tonic-gate  *  output: struct ifslist *: the corresponding ifs, or NULL if not found
5610Sstevel@tonic-gate  */
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate struct ifslist *
5640Sstevel@tonic-gate lookup_ifs_by_xid(uint32_t xid)
5650Sstevel@tonic-gate {
5660Sstevel@tonic-gate 	struct ifslist *ifs;
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	for (ifs = ifsheadp; ifs != NULL; ifs = ifs->next) {
5690Sstevel@tonic-gate 		if (ifs->if_send_pkt.pkt->xid == xid)
5700Sstevel@tonic-gate 			break;
5710Sstevel@tonic-gate 	}
5720Sstevel@tonic-gate 
5730Sstevel@tonic-gate 	return (ifs);
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate /*
577*2546Scarlsonj  * lookup_ifs_by_uindex(): Looks up ifs entries given truncated index and
578*2546Scarlsonj  *			   previous ifs pointer (or NULL for list start).
579*2546Scarlsonj  *			   Caller is expected to iterate through all
580*2546Scarlsonj  *			   potential matches to find interface of interest.
581*2546Scarlsonj  *
582*2546Scarlsonj  *   input: int: the interface index
583*2546Scarlsonj  *	    struct ifslist *: the previous ifs, or NULL for list start
584*2546Scarlsonj  *  output: struct ifslist *: the next matching ifs, or NULL if not found
585*2546Scarlsonj  *    note: This operates using the 'truncated' (16-bit) ifindex as seen by
586*2546Scarlsonj  *	    routing socket clients.  The value stored in if_index is the
587*2546Scarlsonj  *	    32-bit ifindex from the ioctl interface.
588*2546Scarlsonj  */
589*2546Scarlsonj 
590*2546Scarlsonj struct ifslist *
591*2546Scarlsonj lookup_ifs_by_uindex(uint16_t ifindex, struct ifslist *ifs)
592*2546Scarlsonj {
593*2546Scarlsonj 	if (ifs == NULL)
594*2546Scarlsonj 		ifs = ifsheadp;
595*2546Scarlsonj 	else
596*2546Scarlsonj 		ifs = ifs->next;
597*2546Scarlsonj 
598*2546Scarlsonj 	for (; ifs != NULL; ifs = ifs->next) {
599*2546Scarlsonj 		if ((ifs->if_index & 0xffff) == ifindex)
600*2546Scarlsonj 			break;
601*2546Scarlsonj 	}
602*2546Scarlsonj 
603*2546Scarlsonj 	return (ifs);
604*2546Scarlsonj }
605*2546Scarlsonj 
606*2546Scarlsonj /*
6070Sstevel@tonic-gate  * remove_ifs(): removes a given ifs from the ifslist.  marks the ifs
6080Sstevel@tonic-gate  *		 for being freed (but may not actually free it).
6090Sstevel@tonic-gate  *
6100Sstevel@tonic-gate  *   input: struct ifslist *: the ifs to remove
6110Sstevel@tonic-gate  *  output: void
6120Sstevel@tonic-gate  *    note: see interface.h for a discussion of ifs memory management
6130Sstevel@tonic-gate  */
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate void
6160Sstevel@tonic-gate remove_ifs(struct ifslist *ifsp)
6170Sstevel@tonic-gate {
6180Sstevel@tonic-gate 	struct ifreq	ifr;
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if (ifsp->if_dflags & DHCP_IF_REMOVED)
6210Sstevel@tonic-gate 		return;
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	(void) memset(&ifr, 0, sizeof (struct ifreq));
6240Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifsp->if_name, IFNAMSIZ);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	if (ioctl(ifsp->if_sock_fd, SIOCGIFFLAGS, &ifr) == 0) {
6270Sstevel@tonic-gate 		ifr.ifr_flags &= ~IFF_DHCPRUNNING;
6280Sstevel@tonic-gate 		(void) ioctl(ifsp->if_sock_fd, SIOCSIFFLAGS, &ifr);
6290Sstevel@tonic-gate 	}
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	ifsp->if_dflags |= DHCP_IF_REMOVED;
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 	/*
6340Sstevel@tonic-gate 	 * if we have long term timers, cancel them so that interface
6350Sstevel@tonic-gate 	 * resources can be reclaimed in a reasonable amount of time.
6360Sstevel@tonic-gate 	 */
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	cancel_ifs_timers(ifsp);
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	if (ifsp->prev != NULL)
6410Sstevel@tonic-gate 		ifsp->prev->next = ifsp->next;
6420Sstevel@tonic-gate 	else
6430Sstevel@tonic-gate 		ifsheadp = ifsp->next;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 	if (ifsp->next != NULL)
6460Sstevel@tonic-gate 		ifsp->next->prev = ifsp->prev;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 	ifscount--;
6490Sstevel@tonic-gate 	(void) release_ifs(ifsp);
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	/* no big deal if this fails */
6520Sstevel@tonic-gate 	if (ifscount == 0) {
6530Sstevel@tonic-gate 		inactivity_id = iu_schedule_timer(tq, DHCP_INACTIVITY_WAIT,
6540Sstevel@tonic-gate 		    inactivity_shutdown, NULL);
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate 
6580Sstevel@tonic-gate /*
6590Sstevel@tonic-gate  * hold_ifs(): acquires a hold on an ifs
6600Sstevel@tonic-gate  *
6610Sstevel@tonic-gate  *   input: struct ifslist *: the ifs entry to acquire a hold on
6620Sstevel@tonic-gate  *  output: void
6630Sstevel@tonic-gate  */
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate void
6660Sstevel@tonic-gate hold_ifs(struct ifslist *ifsp)
6670Sstevel@tonic-gate {
6680Sstevel@tonic-gate 	ifsp->if_hold_count++;
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	dhcpmsg(MSG_DEBUG2, "hold_ifs: hold count on %s: %d",
6710Sstevel@tonic-gate 	    ifsp->if_name, ifsp->if_hold_count);
6720Sstevel@tonic-gate }
6730Sstevel@tonic-gate 
6740Sstevel@tonic-gate /*
6750Sstevel@tonic-gate  * release_ifs(): releases a hold previously acquired on an ifs.  if the
6760Sstevel@tonic-gate  *		  hold count reaches 0, the ifs is freed
6770Sstevel@tonic-gate  *
6780Sstevel@tonic-gate  *   input: struct ifslist *: the ifs entry to release the hold on
6790Sstevel@tonic-gate  *  output: int: the number of holds outstanding on the ifs
6800Sstevel@tonic-gate  */
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate int
6830Sstevel@tonic-gate release_ifs(struct ifslist *ifsp)
6840Sstevel@tonic-gate {
6850Sstevel@tonic-gate 	if (ifsp->if_hold_count == 0) {
6860Sstevel@tonic-gate 		dhcpmsg(MSG_CRIT, "release_ifs: extraneous release");
6870Sstevel@tonic-gate 		return (0);
6880Sstevel@tonic-gate 	}
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	if (--ifsp->if_hold_count == 0) {
6910Sstevel@tonic-gate 		free_ifs(ifsp);
6920Sstevel@tonic-gate 		return (0);
6930Sstevel@tonic-gate 	}
6940Sstevel@tonic-gate 
6950Sstevel@tonic-gate 	dhcpmsg(MSG_DEBUG2, "release_ifs: hold count on %s: %d",
6960Sstevel@tonic-gate 	    ifsp->if_name, ifsp->if_hold_count);
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	return (ifsp->if_hold_count);
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate /*
7020Sstevel@tonic-gate  * free_ifs(): frees the memory occupied by an ifs entry
7030Sstevel@tonic-gate  *
7040Sstevel@tonic-gate  *   input: struct ifslist *: the ifs entry to free
7050Sstevel@tonic-gate  *  output: void
7060Sstevel@tonic-gate  */
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate static void
7090Sstevel@tonic-gate free_ifs(struct ifslist *ifsp)
7100Sstevel@tonic-gate {
7110Sstevel@tonic-gate 	dhcpmsg(MSG_DEBUG, "free_ifs: freeing interface %s", ifsp->if_name);
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	free_pkt_list(&ifsp->if_recv_pkt_list);
7140Sstevel@tonic-gate 	if (ifsp->if_ack != ifsp->if_orig_ack)
7150Sstevel@tonic-gate 		free_pkt_list(&ifsp->if_orig_ack);
7160Sstevel@tonic-gate 	free_pkt_list(&ifsp->if_ack);
7170Sstevel@tonic-gate 	free(ifsp->if_send_pkt.pkt);
7180Sstevel@tonic-gate 	free(ifsp->if_cid);
7190Sstevel@tonic-gate 	free(ifsp->if_daddr);
7200Sstevel@tonic-gate 	free(ifsp->if_hwaddr);
7210Sstevel@tonic-gate 	free(ifsp->if_prl);
7220Sstevel@tonic-gate 	free(ifsp->if_reqhost);
7230Sstevel@tonic-gate 	free(ifsp->if_routers);
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	if (ifsp->if_sock_fd != -1)
7260Sstevel@tonic-gate 		(void) close(ifsp->if_sock_fd);
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	if (ifsp->if_sock_ip_fd != -1)
7290Sstevel@tonic-gate 		(void) close(ifsp->if_sock_ip_fd);
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	if (ifsp->if_dlpi_fd != -1)
7320Sstevel@tonic-gate 		(void) dlpi_close(ifsp->if_dlpi_fd);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	free(ifsp);
7350Sstevel@tonic-gate }
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate /*
7380Sstevel@tonic-gate  * checkaddr(): checks if the given address is still set on the given ifs
7390Sstevel@tonic-gate  *
7400Sstevel@tonic-gate  *   input: struct ifslist *: the ifs to check
7410Sstevel@tonic-gate  *	    int: the address to lookup on the interface
7420Sstevel@tonic-gate  *	    struct in_addr *: the address to compare to
7430Sstevel@tonic-gate  *  output: boolean_t: B_TRUE if the address is still set; B_FALSE if not
7440Sstevel@tonic-gate  */
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate static boolean_t
7470Sstevel@tonic-gate checkaddr(struct ifslist *ifsp, int ioccmd, struct in_addr *addr)
7480Sstevel@tonic-gate {
7490Sstevel@tonic-gate 	struct ifreq		ifr;
7500Sstevel@tonic-gate 	struct sockaddr_in 	*sin;
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate 	/* LINTED [ifr_addr is a sockaddr which will be aligned] */
7530Sstevel@tonic-gate 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	(void) memset(&ifr, 0, sizeof (struct ifreq));
7560Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifsp->if_name, IFNAMSIZ);
7570Sstevel@tonic-gate 	ifr.ifr_addr.sa_family = AF_INET;
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	switch (ioctl(ifsp->if_sock_fd, ioccmd, &ifr)) {
7600Sstevel@tonic-gate 	case 0:
7610Sstevel@tonic-gate 		if (sin->sin_addr.s_addr != addr->s_addr)
7620Sstevel@tonic-gate 			return (B_FALSE);
7630Sstevel@tonic-gate 		break;
7640Sstevel@tonic-gate 	case -1:
7650Sstevel@tonic-gate 		if (errno == ENXIO)
7660Sstevel@tonic-gate 			return (B_FALSE);
7670Sstevel@tonic-gate 		break;
7680Sstevel@tonic-gate 	}
7690Sstevel@tonic-gate 	return (B_TRUE);
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate /*
7730Sstevel@tonic-gate  * verify_ifs(): verifies than an ifs is still valid (i.e., has not been
7740Sstevel@tonic-gate  *		 explicitly or implicitly dropped or released)
7750Sstevel@tonic-gate  *
7760Sstevel@tonic-gate  *   input: struct ifslist *: the ifs to verify
7770Sstevel@tonic-gate  *  output: int: 1 if the ifs is still valid, 0 if the interface is invalid
7780Sstevel@tonic-gate  */
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate int
7810Sstevel@tonic-gate verify_ifs(struct ifslist *ifsp)
7820Sstevel@tonic-gate {
7830Sstevel@tonic-gate 	struct ifreq 		ifr;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	if (ifsp->if_dflags & DHCP_IF_REMOVED)
7860Sstevel@tonic-gate 		return (0);
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	(void) memset(&ifr, 0, sizeof (struct ifreq));
7890Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifsp->if_name, IFNAMSIZ);
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	ifr.ifr_addr.sa_family = AF_INET;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	switch (ifsp->if_state) {
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	case BOUND:
7960Sstevel@tonic-gate 	case RENEWING:
7970Sstevel@tonic-gate 	case REBINDING:
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 		/*
8000Sstevel@tonic-gate 		 * if the interface has gone down or been unplumbed, then we
8010Sstevel@tonic-gate 		 * act like there has been an implicit drop.
8020Sstevel@tonic-gate 		 */
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 		switch (ioctl(ifsp->if_sock_fd, SIOCGIFFLAGS, &ifr)) {
8050Sstevel@tonic-gate 		case 0:
8060Sstevel@tonic-gate 			if ((ifr.ifr_flags & (IFF_UP|IFF_DHCPRUNNING)) !=
8070Sstevel@tonic-gate 			    (IFF_UP|IFF_DHCPRUNNING))
8080Sstevel@tonic-gate 				goto abandon;
8090Sstevel@tonic-gate 			break;
8100Sstevel@tonic-gate 		case -1:
8110Sstevel@tonic-gate 			if (errno == ENXIO)
8120Sstevel@tonic-gate 				goto abandon;
8130Sstevel@tonic-gate 			break;
8140Sstevel@tonic-gate 		}
815*2546Scarlsonj 		switch (ioctl(ifsp->if_sock_fd, SIOCGIFINDEX, &ifr)) {
816*2546Scarlsonj 		case 0:
817*2546Scarlsonj 			if (ifr.ifr_index != ifsp->if_index)
818*2546Scarlsonj 				goto abandon;
819*2546Scarlsonj 			break;
820*2546Scarlsonj 		case -1:
821*2546Scarlsonj 			if (errno == ENXIO)
822*2546Scarlsonj 				goto abandon;
823*2546Scarlsonj 			break;
824*2546Scarlsonj 		}
8250Sstevel@tonic-gate 		/* FALLTHRU */
8260Sstevel@tonic-gate 
8270Sstevel@tonic-gate 	case INIT_REBOOT:
8280Sstevel@tonic-gate 	case SELECTING:
8290Sstevel@tonic-gate 	case REQUESTING:
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 		/*
8320Sstevel@tonic-gate 		 * if the IP address, netmask, or broadcast address have
8330Sstevel@tonic-gate 		 * changed, or the interface has been unplumbed, then we act
8340Sstevel@tonic-gate 		 * like there has been an implicit drop.
8350Sstevel@tonic-gate 		 */
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 		if (!checkaddr(ifsp, SIOCGIFADDR, &ifsp->if_addr) ||
8380Sstevel@tonic-gate 		    !checkaddr(ifsp, SIOCGIFNETMASK, &ifsp->if_netmask) ||
8390Sstevel@tonic-gate 		    !checkaddr(ifsp, SIOCGIFBRDADDR, &ifsp->if_broadcast))
8400Sstevel@tonic-gate 			goto abandon;
8410Sstevel@tonic-gate 	}
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	return (1);
8440Sstevel@tonic-gate abandon:
8450Sstevel@tonic-gate 	dhcpmsg(MSG_WARNING, "verify_ifs: %s has changed properties, "
8460Sstevel@tonic-gate 	    "abandoning", ifsp->if_name);
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	remove_ifs(ifsp);
8490Sstevel@tonic-gate 	return (0);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate /*
8530Sstevel@tonic-gate  * canonize_ifs(): puts the interface in a canonical (zeroed) form
8540Sstevel@tonic-gate  *
8550Sstevel@tonic-gate  *   input: struct ifslist *: the interface to canonize
8560Sstevel@tonic-gate  *  output: int: 1 on success, 0 on failure
8570Sstevel@tonic-gate  */
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate int
8600Sstevel@tonic-gate canonize_ifs(struct ifslist *ifsp)
8610Sstevel@tonic-gate {
8620Sstevel@tonic-gate 	struct sockaddr_in	*sin;
8630Sstevel@tonic-gate 	struct ifreq		ifr;
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	dhcpmsg(MSG_VERBOSE, "canonizing interface %s", ifsp->if_name);
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	/*
8680Sstevel@tonic-gate 	 * note that due to infelicities in the routing code, any default
8690Sstevel@tonic-gate 	 * routes must be removed prior to clearing the UP flag.
8700Sstevel@tonic-gate 	 */
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	remove_ifs_default_routes(ifsp);
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	/* LINTED [ifr_addr is a sockaddr which will be aligned] */
8750Sstevel@tonic-gate 	sin = (struct sockaddr_in *)&ifr.ifr_addr;
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	(void) memset(&ifr, 0, sizeof (struct ifreq));
8780Sstevel@tonic-gate 	(void) strlcpy(ifr.ifr_name, ifsp->if_name, IFNAMSIZ);
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	if (ioctl(ifsp->if_sock_fd, SIOCGIFFLAGS, &ifr) == -1)
8810Sstevel@tonic-gate 		return (0);
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	/*
8840Sstevel@tonic-gate 	 * clear the UP flag, but don't clear DHCPRUNNING since
8850Sstevel@tonic-gate 	 * that should only be done when the interface is removed
8860Sstevel@tonic-gate 	 * (see remove_ifs())
8870Sstevel@tonic-gate 	 */
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	ifr.ifr_flags &= ~IFF_UP;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	if (ioctl(ifsp->if_sock_fd, SIOCSIFFLAGS, &ifr) == -1)
8920Sstevel@tonic-gate 		return (0);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	/*
8950Sstevel@tonic-gate 	 * since ifr is actually a union, we need to explicitly zero
8960Sstevel@tonic-gate 	 * the flags field before we reuse the structure, or otherwise
8970Sstevel@tonic-gate 	 * cruft may leak over into other members of the union.
8980Sstevel@tonic-gate 	 */
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	ifr.ifr_flags = 0;
9010Sstevel@tonic-gate 	ifr.ifr_addr.sa_family = AF_INET;
9020Sstevel@tonic-gate 	sin->sin_addr.s_addr = htonl(INADDR_ANY);
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	if (ioctl(ifsp->if_sock_fd, SIOCSIFADDR, &ifr) == -1)
9050Sstevel@tonic-gate 		return (0);
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	if (ioctl(ifsp->if_sock_fd, SIOCSIFNETMASK, &ifr) == -1)
9080Sstevel@tonic-gate 		return (0);
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	if (ioctl(ifsp->if_sock_fd, SIOCSIFBRDADDR, &ifr) == -1)
9110Sstevel@tonic-gate 		return (0);
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 	/*
9140Sstevel@tonic-gate 	 * any time we change the IP address, netmask, or broadcast we
9150Sstevel@tonic-gate 	 * must be careful to also reset bookkeeping of what these are
9160Sstevel@tonic-gate 	 * set to.  this is so we can detect if these characteristics
9170Sstevel@tonic-gate 	 * are changed by another process.
9180Sstevel@tonic-gate 	 */
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	ifsp->if_addr.s_addr	  = htonl(INADDR_ANY);
9210Sstevel@tonic-gate 	ifsp->if_netmask.s_addr   = htonl(INADDR_ANY);
9220Sstevel@tonic-gate 	ifsp->if_broadcast.s_addr = htonl(INADDR_ANY);
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	return (1);
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate /*
9280Sstevel@tonic-gate  * check_ifs(): makes sure an ifs is still valid, and if it is, releases the
9290Sstevel@tonic-gate  *		ifs.  otherwise, it informs the caller the ifs is going away
9300Sstevel@tonic-gate  *		and expects the caller to perform the release
9310Sstevel@tonic-gate  *
9320Sstevel@tonic-gate  *   input: struct ifslist *: the ifs to check
9330Sstevel@tonic-gate  *  output: int: 1 if the interface is valid, 0 otherwise
9340Sstevel@tonic-gate  */
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate int
9370Sstevel@tonic-gate check_ifs(struct ifslist *ifsp)
9380Sstevel@tonic-gate {
9390Sstevel@tonic-gate 	hold_ifs(ifsp);
9400Sstevel@tonic-gate 	if (release_ifs(ifsp) == 1 || verify_ifs(ifsp) == 0) {
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 		/*
9430Sstevel@tonic-gate 		 * this interface is going away.  if there's an
9440Sstevel@tonic-gate 		 * uncancelled IPC event roaming around, cancel it
9450Sstevel@tonic-gate 		 * now.  we leave the hold on in case anyone else has
9460Sstevel@tonic-gate 		 * any cleanup work that needs to be done before the
9470Sstevel@tonic-gate 		 * interface goes away.
9480Sstevel@tonic-gate 		 */
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate 		ipc_action_finish(ifsp, DHCP_IPC_E_UNKIF);
9510Sstevel@tonic-gate 		async_finish(ifsp);
9520Sstevel@tonic-gate 		return (0);
9530Sstevel@tonic-gate 	}
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	(void) release_ifs(ifsp);
9560Sstevel@tonic-gate 	return (1);
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate /*
9600Sstevel@tonic-gate  * nuke_ifslist(): delete the ifslist (for use when the dhcpagent is exiting)
9610Sstevel@tonic-gate  *
9620Sstevel@tonic-gate  *   input: boolean_t: B_TRUE if the agent is exiting due to SIGTERM
9630Sstevel@tonic-gate  *  output: void
9640Sstevel@tonic-gate  */
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate void
9670Sstevel@tonic-gate nuke_ifslist(boolean_t onterm)
9680Sstevel@tonic-gate {
9690Sstevel@tonic-gate 	int	status;
9700Sstevel@tonic-gate 	struct ifslist	*ifsp, *ifsp_next;
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	for (ifsp = ifsheadp; ifsp != NULL; ifsp = ifsp_next) {
9730Sstevel@tonic-gate 		ifsp_next = ifsp->next;
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 		cancel_ifs_timers(ifsp);
9760Sstevel@tonic-gate 		if (ifsp->if_script_pid != -1) {
9770Sstevel@tonic-gate 			/* stop a script if it is not for DROP or RELEASE */
9780Sstevel@tonic-gate 			if (strcmp(ifsp->if_script_event, EVENT_DROP) == 0 ||
9790Sstevel@tonic-gate 			    strcmp(ifsp->if_script_event, EVENT_RELEASE) == 0) {
9800Sstevel@tonic-gate 				continue;
9810Sstevel@tonic-gate 			}
9820Sstevel@tonic-gate 			script_stop(ifsp);
9830Sstevel@tonic-gate 		}
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 		/*
9860Sstevel@tonic-gate 		 * if the script is started by script_start, dhcp_drop and
9870Sstevel@tonic-gate 		 * dhcp_release should and will only be called after the
9880Sstevel@tonic-gate 		 * script exits.
9890Sstevel@tonic-gate 		 */
9900Sstevel@tonic-gate 		if (onterm &&
9910Sstevel@tonic-gate 		    df_get_bool(ifsp->if_name, DF_RELEASE_ON_SIGTERM)) {
9920Sstevel@tonic-gate 			if (script_start(ifsp, EVENT_RELEASE, dhcp_release,
9930Sstevel@tonic-gate 			    "DHCP agent is exiting", &status) == 1) {
9940Sstevel@tonic-gate 				continue;
9950Sstevel@tonic-gate 			}
9960Sstevel@tonic-gate 			if (status == 1)
9970Sstevel@tonic-gate 				continue;
9980Sstevel@tonic-gate 		}
9990Sstevel@tonic-gate 		(void) script_start(ifsp, EVENT_DROP, dhcp_drop, NULL, NULL);
10000Sstevel@tonic-gate 	}
10010Sstevel@tonic-gate }
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate /*
10040Sstevel@tonic-gate  * refresh_ifslist(): refreshes all finite leases under DHCP control
10050Sstevel@tonic-gate  *
10060Sstevel@tonic-gate  *   input: iu_eh_t *: unused
10070Sstevel@tonic-gate  *	    int: unused
10080Sstevel@tonic-gate  *	    void *: unused
10090Sstevel@tonic-gate  *  output: void
10100Sstevel@tonic-gate  */
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate /* ARGSUSED */
10130Sstevel@tonic-gate void
10140Sstevel@tonic-gate refresh_ifslist(iu_eh_t *eh, int sig, void *arg)
10150Sstevel@tonic-gate {
10160Sstevel@tonic-gate 	struct ifslist *ifsp;
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	for (ifsp = ifsheadp; ifsp != NULL; ifsp = ifsp->next) {
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 		if (ifsp->if_state != BOUND && ifsp->if_state != RENEWING &&
10210Sstevel@tonic-gate 		    ifsp->if_state != REBINDING)
10220Sstevel@tonic-gate 			continue;
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 		if (ifsp->if_lease == DHCP_PERM)
10250Sstevel@tonic-gate 			continue;
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 		/*
10280Sstevel@tonic-gate 		 * this interface has a finite lease and we do not know
10290Sstevel@tonic-gate 		 * how long the machine's been off for.  refresh it.
10300Sstevel@tonic-gate 		 */
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 		dhcpmsg(MSG_WARNING, "refreshing lease on %s", ifsp->if_name);
10330Sstevel@tonic-gate 		cancel_ifs_timer(ifsp, DHCP_T1_TIMER);
10340Sstevel@tonic-gate 		cancel_ifs_timer(ifsp, DHCP_T2_TIMER);
10350Sstevel@tonic-gate 		(void) iu_adjust_timer(tq, ifsp->if_timer[DHCP_LEASE_TIMER], 0);
10360Sstevel@tonic-gate 	}
10370Sstevel@tonic-gate }
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate /*
10400Sstevel@tonic-gate  * ifs_count(): returns the number of interfaces currently managed
10410Sstevel@tonic-gate  *
10420Sstevel@tonic-gate  *   input: void
10430Sstevel@tonic-gate  *  output: unsigned int: the number of interfaces currently managed
10440Sstevel@tonic-gate  */
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate unsigned int
10470Sstevel@tonic-gate ifs_count(void)
10480Sstevel@tonic-gate {
10490Sstevel@tonic-gate 	return (ifscount);
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate /*
10530Sstevel@tonic-gate  * cancel_ifs_timer(): cancels a lease-related timer on an interface
10540Sstevel@tonic-gate  *
10550Sstevel@tonic-gate  *   input: struct ifslist *: the interface to operate on
10560Sstevel@tonic-gate  *	    int: the timer id of the timer to cancel
10570Sstevel@tonic-gate  *  output: void
10580Sstevel@tonic-gate  */
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate static void
10610Sstevel@tonic-gate cancel_ifs_timer(struct ifslist *ifsp, int timer_id)
10620Sstevel@tonic-gate {
10630Sstevel@tonic-gate 	if (ifsp->if_timer[timer_id] != -1) {
10640Sstevel@tonic-gate 		if (iu_cancel_timer(tq, ifsp->if_timer[timer_id], NULL) == 1) {
10650Sstevel@tonic-gate 			(void) release_ifs(ifsp);
10660Sstevel@tonic-gate 			ifsp->if_timer[timer_id] = -1;
10670Sstevel@tonic-gate 		} else
10680Sstevel@tonic-gate 			dhcpmsg(MSG_WARNING, "cancel_ifs_timer: cannot cancel "
10690Sstevel@tonic-gate 			    "if_timer[%d]", timer_id);
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate }
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate  * cancel_ifs_timers(): cancels an interface's pending lease-related timers
10750Sstevel@tonic-gate  *
10760Sstevel@tonic-gate  *   input: struct ifslist *: the interface to operate on
10770Sstevel@tonic-gate  *  output: void
10780Sstevel@tonic-gate  */
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate void
10810Sstevel@tonic-gate cancel_ifs_timers(struct ifslist *ifsp)
10820Sstevel@tonic-gate {
10830Sstevel@tonic-gate 	cancel_ifs_timer(ifsp, DHCP_T1_TIMER);
10840Sstevel@tonic-gate 	cancel_ifs_timer(ifsp, DHCP_T2_TIMER);
10850Sstevel@tonic-gate 	cancel_ifs_timer(ifsp, DHCP_LEASE_TIMER);
10860Sstevel@tonic-gate }
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate /*
10890Sstevel@tonic-gate  * schedule_ifs_timer(): schedules a lease-related timer on an interface
10900Sstevel@tonic-gate  *
10910Sstevel@tonic-gate  *   input: struct ifslist *: the interface to operate on
10920Sstevel@tonic-gate  *	    int: the timer to schedule
10930Sstevel@tonic-gate  *	    uint32_t: the number of seconds in the future it should fire
10940Sstevel@tonic-gate  *	    iu_tq_callback_t *: the callback to call upon firing
10950Sstevel@tonic-gate  *  output: int: 1 if the timer was scheduled successfully, 0 on failure
10960Sstevel@tonic-gate  */
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate int
10990Sstevel@tonic-gate schedule_ifs_timer(struct ifslist *ifsp, int timer_id, uint32_t sec,
11000Sstevel@tonic-gate     iu_tq_callback_t *expire)
11010Sstevel@tonic-gate {
11020Sstevel@tonic-gate 	cancel_ifs_timer(ifsp, timer_id);		/* just in case */
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	ifsp->if_timer[timer_id] = iu_schedule_timer(tq, sec, expire, ifsp);
11050Sstevel@tonic-gate 	if (ifsp->if_timer[timer_id] == -1) {
11060Sstevel@tonic-gate 		dhcpmsg(MSG_WARNING, "schedule_ifs_timer: cannot schedule "
11070Sstevel@tonic-gate 		    "if_timer[%d]", timer_id);
11080Sstevel@tonic-gate 		return (0);
11090Sstevel@tonic-gate 	}
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	hold_ifs(ifsp);
11120Sstevel@tonic-gate 	return (1);
11130Sstevel@tonic-gate }
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate /*
11160Sstevel@tonic-gate  * Get the value of the named property on the named node in devinfo root.
11170Sstevel@tonic-gate  *
11180Sstevel@tonic-gate  *   input: const char *: The name of the node containing the property.
11190Sstevel@tonic-gate  *	    const char *: The name of the property.
11200Sstevel@tonic-gate  *	    uchar_t **: The property value, modified iff B_TRUE is returned.
11210Sstevel@tonic-gate  *                      If no value is found the value is set to NULL.
11220Sstevel@tonic-gate  *	    unsigned int *: The length of the property value
11230Sstevel@tonic-gate  *  output: boolean_t: Returns B_TRUE if successful (no problems),
11240Sstevel@tonic-gate  *                     otherwise B_FALSE.
11250Sstevel@tonic-gate  *    note: The memory allocated by this function must be freed by
11260Sstevel@tonic-gate  *          the caller. This code is derived from
11270Sstevel@tonic-gate  *          usr/src/lib/libwanboot/common/bootinfo_aux.c.
11280Sstevel@tonic-gate  */
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate static boolean_t
11310Sstevel@tonic-gate get_prom_prop(const char *nodename, const char *propname, uchar_t **propvaluep,
11320Sstevel@tonic-gate     unsigned int *lenp)
11330Sstevel@tonic-gate {
11340Sstevel@tonic-gate 	di_node_t		root_node = DI_NODE_NIL;
11350Sstevel@tonic-gate 	di_node_t		node;
11360Sstevel@tonic-gate 	di_prom_handle_t	phdl = DI_PROM_HANDLE_NIL;
11370Sstevel@tonic-gate 	di_prom_prop_t		pp;
11380Sstevel@tonic-gate 	uchar_t			*value = NULL;
11390Sstevel@tonic-gate 	unsigned int		len = 0;
11400Sstevel@tonic-gate 	boolean_t		success = B_TRUE;
11410Sstevel@tonic-gate 
11420Sstevel@tonic-gate 	/*
11430Sstevel@tonic-gate 	 * locate root node
11440Sstevel@tonic-gate 	 */
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	if ((root_node = di_init("/", DINFOCPYALL)) == DI_NODE_NIL ||
11470Sstevel@tonic-gate 	    (phdl = di_prom_init()) == DI_PROM_HANDLE_NIL) {
11480Sstevel@tonic-gate 		dhcpmsg(MSG_DEBUG, "get_prom_prop: property root node "
11490Sstevel@tonic-gate 		    "not found");
11500Sstevel@tonic-gate 		goto get_prom_prop_cleanup;
11510Sstevel@tonic-gate 	}
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	/*
11540Sstevel@tonic-gate 	 * locate nodename within '/'
11550Sstevel@tonic-gate 	 */
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	for (node = di_child_node(root_node);
11580Sstevel@tonic-gate 	    node != DI_NODE_NIL;
11590Sstevel@tonic-gate 	    node = di_sibling_node(node)) {
11600Sstevel@tonic-gate 		if (strcmp(di_node_name(node), nodename) == 0) {
11610Sstevel@tonic-gate 			break;
11620Sstevel@tonic-gate 		}
11630Sstevel@tonic-gate 	}
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	if (node == DI_NODE_NIL) {
11660Sstevel@tonic-gate 		dhcpmsg(MSG_DEBUG, "get_prom_prop: node not found");
11670Sstevel@tonic-gate 		goto get_prom_prop_cleanup;
11680Sstevel@tonic-gate 	}
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	/*
11710Sstevel@tonic-gate 	 * scan all properties of /nodename for the 'propname' property
11720Sstevel@tonic-gate 	 */
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	for (pp = di_prom_prop_next(phdl, node, DI_PROM_PROP_NIL);
11750Sstevel@tonic-gate 	    pp != DI_PROM_PROP_NIL;
11760Sstevel@tonic-gate 	    pp = di_prom_prop_next(phdl, node, pp)) {
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 		dhcpmsg(MSG_DEBUG, "get_prom_prop: property = %s",
11790Sstevel@tonic-gate 		    di_prom_prop_name(pp));
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 		if (strcmp(propname, di_prom_prop_name(pp)) == 0) {
11820Sstevel@tonic-gate 			break;
11830Sstevel@tonic-gate 		}
11840Sstevel@tonic-gate 	}
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	if (pp == DI_PROM_PROP_NIL) {
11870Sstevel@tonic-gate 		dhcpmsg(MSG_DEBUG, "get_prom_prop: property not found");
11880Sstevel@tonic-gate 		goto get_prom_prop_cleanup;
11890Sstevel@tonic-gate 	}
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	/*
11920Sstevel@tonic-gate 	 * get the property; allocate some memory copy it out
11930Sstevel@tonic-gate 	 */
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	len = di_prom_prop_data(pp, (uchar_t **)&value);
11960Sstevel@tonic-gate 
11970Sstevel@tonic-gate 	if (value == NULL) {
11980Sstevel@tonic-gate 		/*
11990Sstevel@tonic-gate 		 * property data read problems
12000Sstevel@tonic-gate 		 */
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 		success = B_FALSE;
12030Sstevel@tonic-gate 		dhcpmsg(MSG_ERR, "get_prom_prop: cannot read property data");
12040Sstevel@tonic-gate 		goto get_prom_prop_cleanup;
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate 
12070Sstevel@tonic-gate 	if (propvaluep != NULL) {
12080Sstevel@tonic-gate 		/*
12090Sstevel@tonic-gate 		 * allocate somewhere to copy the property value to
12100Sstevel@tonic-gate 		 */
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 		*propvaluep = calloc(len, sizeof (uchar_t));
12130Sstevel@tonic-gate 
12140Sstevel@tonic-gate 		if (*propvaluep == NULL) {
12150Sstevel@tonic-gate 			/*
12160Sstevel@tonic-gate 			 * allocation problems
12170Sstevel@tonic-gate 			 */
12180Sstevel@tonic-gate 
12190Sstevel@tonic-gate 			success = B_FALSE;
12200Sstevel@tonic-gate 			dhcpmsg(MSG_ERR, "get_prom_prop: cannot allocate "
12210Sstevel@tonic-gate 			    "memory for property value");
12220Sstevel@tonic-gate 			goto get_prom_prop_cleanup;
12230Sstevel@tonic-gate 		}
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 		/*
12260Sstevel@tonic-gate 		 * copy data out
12270Sstevel@tonic-gate 		 */
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 		(void) memcpy(*propvaluep, value, len);
12300Sstevel@tonic-gate 
12310Sstevel@tonic-gate 		/*
12320Sstevel@tonic-gate 		 * copy out the length if a suitable pointer has
12330Sstevel@tonic-gate 		 * been supplied
12340Sstevel@tonic-gate 		 */
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 		if (lenp != NULL) {
12370Sstevel@tonic-gate 			*lenp = len;
12380Sstevel@tonic-gate 		}
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate 		dhcpmsg(MSG_DEBUG, "get_prom_prop: property value "
12410Sstevel@tonic-gate 		    "length = %d", len);
12420Sstevel@tonic-gate 	}
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate get_prom_prop_cleanup:
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	if (phdl != DI_PROM_HANDLE_NIL) {
12470Sstevel@tonic-gate 		di_prom_fini(phdl);
12480Sstevel@tonic-gate 	}
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	if (root_node != DI_NODE_NIL) {
12510Sstevel@tonic-gate 		di_fini(root_node);
12520Sstevel@tonic-gate 	}
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	return (success);
12550Sstevel@tonic-gate }
1256