xref: /titanic_51/usr/src/cmd/rcm_daemon/common/ip_rcm.c (revision 64639aaf7beb84086b88f186ea1fa9ccf0be8c57)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5392b1d6eSyz147064  * Common Development and Distribution License (the "License").
6392b1d6eSyz147064  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*64639aafSDarren Reed  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate /*
267c478bd9Sstevel@tonic-gate  * This RCM module adds support to the RCM framework for IP managed
277c478bd9Sstevel@tonic-gate  * interfaces.
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include <stdio.h>
317c478bd9Sstevel@tonic-gate #include <stdlib.h>
327c478bd9Sstevel@tonic-gate #include <unistd.h>
337c478bd9Sstevel@tonic-gate #include <assert.h>
347c478bd9Sstevel@tonic-gate #include <string.h>
357c478bd9Sstevel@tonic-gate #include <synch.h>
367c478bd9Sstevel@tonic-gate #include <libintl.h>
377c478bd9Sstevel@tonic-gate #include <errno.h>
387c478bd9Sstevel@tonic-gate #include <fcntl.h>
397c478bd9Sstevel@tonic-gate #include <sys/types.h>
40e11c3f44Smeem #include <sys/wait.h>
417c478bd9Sstevel@tonic-gate #include <sys/stat.h>
427c478bd9Sstevel@tonic-gate #include <sys/socket.h>
437c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
447c478bd9Sstevel@tonic-gate #include <net/if.h>
457c478bd9Sstevel@tonic-gate #include <netinet/in.h>
467c478bd9Sstevel@tonic-gate #include <arpa/inet.h>
477c478bd9Sstevel@tonic-gate #include <stropts.h>
487c478bd9Sstevel@tonic-gate #include <strings.h>
49e11c3f44Smeem #include <sys/sysmacros.h>
50ff550d0eSmasputra #include <inet/ip.h>
51595aa6e4Smeem #include <libinetutil.h>
52d62bc4baSyz147064 #include <libdllink.h>
53e11c3f44Smeem #include <libgen.h>
54e11c3f44Smeem #include <ipmp_admin.h>
556e91bba0SGirish Moodalbail #include <libipadm.h>
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate #include "rcm_module.h"
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * Definitions
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate #ifndef lint
637c478bd9Sstevel@tonic-gate #define	_(x)	gettext(x)
647c478bd9Sstevel@tonic-gate #else
657c478bd9Sstevel@tonic-gate #define	_(x)	x
667c478bd9Sstevel@tonic-gate #endif
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /* Some generic well-knowns and defaults used in this module */
697c478bd9Sstevel@tonic-gate #define	ARP_MOD_NAME		"arp"		/* arp module */
707c478bd9Sstevel@tonic-gate #define	IP_MAX_MODS		9		/* max modules pushed on intr */
717c478bd9Sstevel@tonic-gate #define	MAX_RECONFIG_SIZE	1024		/* Max. reconfig string size */
727c478bd9Sstevel@tonic-gate 
73d62bc4baSyz147064 #define	RCM_LINK_PREFIX		"SUNW_datalink"	/* RCM datalink name prefix */
74d62bc4baSyz147064 #define	RCM_LINK_RESOURCE_MAX	(13 + LINKID_STR_WIDTH)
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate #define	RCM_STR_SUNW_IP		"SUNW_ip/"	/* IP address export prefix */
777c478bd9Sstevel@tonic-gate 
78e11c3f44Smeem #define	SBIN_IFCONFIG		"/sbin/ifconfig" /* ifconfig command */
79e11c3f44Smeem #define	SBIN_IFPARSE		"/sbin/ifparse"	/* ifparse command */
80e11c3f44Smeem #define	DHCPFILE_FMT		"/etc/dhcp.%s"	/* DHCP config file */
81e11c3f44Smeem #define	CFGFILE_FMT_IPV4	"/etc/hostname.%s"  /* IPV4 config file */
82e11c3f44Smeem #define	CFGFILE_FMT_IPV6	"/etc/hostname6.%s" /* IPV6 config file */
837c478bd9Sstevel@tonic-gate #define	CFG_CMDS_STD	" netmask + broadcast + up" /* Normal config string */
84e11c3f44Smeem #define	CFG_DHCP_CMD		"dhcp wait 0"	/* command to start DHCP */
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate /* Some useful macros */
877c478bd9Sstevel@tonic-gate #define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
887c478bd9Sstevel@tonic-gate #define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
897c478bd9Sstevel@tonic-gate #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate /* Interface Cache state flags */
927c478bd9Sstevel@tonic-gate #define	CACHE_IF_STALE		0x1		/* stale cached data */
937c478bd9Sstevel@tonic-gate #define	CACHE_IF_NEW		0x2		/* new cached interface */
947c478bd9Sstevel@tonic-gate #define	CACHE_IF_OFFLINED	0x4		/* interface offlined */
95392b1d6eSyz147064 #define	CACHE_IF_IGNORE		0x8		/* state held elsewhere */
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /* Network Cache lookup options */
987c478bd9Sstevel@tonic-gate #define	CACHE_NO_REFRESH	0x1		/* cache refresh not needed */
997c478bd9Sstevel@tonic-gate #define	CACHE_REFRESH		0x2		/* refresh cache */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /* RCM IPMP Module specific property definitions */
1027c478bd9Sstevel@tonic-gate #define	RCM_IPMP_MIN_REDUNDANCY	1		/* default min. redundancy */
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /* Stream module operations */
1057c478bd9Sstevel@tonic-gate #define	MOD_INSERT		0	/* Insert a mid-stream module */
1067c478bd9Sstevel@tonic-gate #define	MOD_REMOVE		1	/* Remove a mid-stream module */
1077c478bd9Sstevel@tonic-gate #define	MOD_CHECK		2	/* Check mid-stream module safety */
1087c478bd9Sstevel@tonic-gate 
1097c478bd9Sstevel@tonic-gate /*
1107c478bd9Sstevel@tonic-gate  * IP module data types
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /* Physical interface representation */
1147c478bd9Sstevel@tonic-gate typedef struct ip_pif {
115e11c3f44Smeem 	char		pi_ifname[LIFNAMSIZ];	/* interface name */
116e11c3f44Smeem 	char		pi_grname[LIFGRNAMSIZ]; /* IPMP group name */
1177c478bd9Sstevel@tonic-gate 	struct ip_lif	*pi_lifs;		/* ptr to logical interfaces */
1187c478bd9Sstevel@tonic-gate } ip_pif_t;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate /* Logical interface representation */
1217c478bd9Sstevel@tonic-gate typedef struct ip_lif
1227c478bd9Sstevel@tonic-gate {
1237c478bd9Sstevel@tonic-gate 	struct ip_lif		*li_next;	/* ptr to next lif */
1247c478bd9Sstevel@tonic-gate 	struct ip_lif		*li_prev;  	/* previous next ptr */
1257c478bd9Sstevel@tonic-gate 	ip_pif_t		*li_pif;	/* back ptr to phy int */
1267c478bd9Sstevel@tonic-gate 	ushort_t		li_ifnum;	/* interface number */
1277c478bd9Sstevel@tonic-gate 	union {
1287c478bd9Sstevel@tonic-gate 		sa_family_t		family;
1297c478bd9Sstevel@tonic-gate 		struct sockaddr_storage storage;
1307c478bd9Sstevel@tonic-gate 		struct sockaddr_in	ip4;    /* IPv4 */
1317c478bd9Sstevel@tonic-gate 		struct sockaddr_in6	ip6;    /* IPv6 */
1327c478bd9Sstevel@tonic-gate 	} li_addr;
1337c478bd9Sstevel@tonic-gate 	uint64_t		li_ifflags;	/* current IFF_* flags */
1347c478bd9Sstevel@tonic-gate 	int			li_modcnt;	/* # of modules */
1357c478bd9Sstevel@tonic-gate 	char	*li_modules[IP_MAX_MODS];	/* module list pushed */
1367c478bd9Sstevel@tonic-gate 	char	*li_reconfig;			/* Reconfiguration string */
1377c478bd9Sstevel@tonic-gate 	int32_t			li_cachestate;	/* cache state flags */
1387c478bd9Sstevel@tonic-gate } ip_lif_t;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /* Cache element */
1417c478bd9Sstevel@tonic-gate typedef struct ip_cache
1427c478bd9Sstevel@tonic-gate {
1437c478bd9Sstevel@tonic-gate 	struct ip_cache		*ip_next;	/* next cached resource */
1447c478bd9Sstevel@tonic-gate 	struct ip_cache		*ip_prev;	/* prev cached resource */
1457c478bd9Sstevel@tonic-gate 	char			*ip_resource;	/* resource name */
1467c478bd9Sstevel@tonic-gate 	ip_pif_t		*ip_pif;	/* ptr to phy int */
1477c478bd9Sstevel@tonic-gate 	int32_t			ip_ifred;	/* min. redundancy */
1487c478bd9Sstevel@tonic-gate 	int			ip_cachestate;	/* cache state flags */
1497c478bd9Sstevel@tonic-gate } ip_cache_t;
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate /*
1527c478bd9Sstevel@tonic-gate  * Global cache for network interfaces
1537c478bd9Sstevel@tonic-gate  */
1547c478bd9Sstevel@tonic-gate static ip_cache_t	cache_head;
1557c478bd9Sstevel@tonic-gate static ip_cache_t	cache_tail;
1567c478bd9Sstevel@tonic-gate static mutex_t		cache_lock;
1577c478bd9Sstevel@tonic-gate static int		events_registered = 0;
1587c478bd9Sstevel@tonic-gate 
1594ac67f02SAnurag S. Maskey static dladm_handle_t	dld_handle = NULL;
1606e91bba0SGirish Moodalbail static ipadm_handle_t	ip_handle = NULL;
1614ac67f02SAnurag S. Maskey 
1627c478bd9Sstevel@tonic-gate /*
1637c478bd9Sstevel@tonic-gate  * RCM module interface prototypes
1647c478bd9Sstevel@tonic-gate  */
1657c478bd9Sstevel@tonic-gate static int ip_register(rcm_handle_t *);
1667c478bd9Sstevel@tonic-gate static int ip_unregister(rcm_handle_t *);
1677c478bd9Sstevel@tonic-gate static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t,
1687c478bd9Sstevel@tonic-gate 			char **, char **, nvlist_t *, rcm_info_t **);
1697c478bd9Sstevel@tonic-gate static int ip_suspend(rcm_handle_t *, char *, id_t,
1707c478bd9Sstevel@tonic-gate 			timespec_t *, uint_t, char **, rcm_info_t **);
1717c478bd9Sstevel@tonic-gate static int ip_resume(rcm_handle_t *, char *, id_t, uint_t,
1727c478bd9Sstevel@tonic-gate 			char **, rcm_info_t **);
1737c478bd9Sstevel@tonic-gate static int ip_offline(rcm_handle_t *, char *, id_t, uint_t,
1747c478bd9Sstevel@tonic-gate 			char **, rcm_info_t **);
1757c478bd9Sstevel@tonic-gate static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
1767c478bd9Sstevel@tonic-gate 			char **, rcm_info_t **);
1777c478bd9Sstevel@tonic-gate static int ip_remove(rcm_handle_t *, char *, id_t, uint_t,
1787c478bd9Sstevel@tonic-gate 			char **, rcm_info_t **);
1797c478bd9Sstevel@tonic-gate static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t,
1807c478bd9Sstevel@tonic-gate 			char **, nvlist_t *, rcm_info_t **);
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate /* Module private routines */
1837c478bd9Sstevel@tonic-gate static void 	free_cache();
1847c478bd9Sstevel@tonic-gate static int 	update_cache(rcm_handle_t *);
1857c478bd9Sstevel@tonic-gate static void 	cache_remove(ip_cache_t *);
1867c478bd9Sstevel@tonic-gate static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char);
1877c478bd9Sstevel@tonic-gate static void 	free_node(ip_cache_t *);
1887c478bd9Sstevel@tonic-gate static void 	cache_insert(ip_cache_t *);
1897c478bd9Sstevel@tonic-gate static char 	*ip_usage(ip_cache_t *);
1906e91bba0SGirish Moodalbail static int 	update_pif(rcm_handle_t *, int, int, struct ifaddrs *);
191e11c3f44Smeem static int 	ip_ipmp_offline(ip_cache_t *);
1927c478bd9Sstevel@tonic-gate static int	ip_ipmp_undo_offline(ip_cache_t *);
1937c478bd9Sstevel@tonic-gate static int	if_cfginfo(ip_cache_t *, uint_t);
1947c478bd9Sstevel@tonic-gate static int	if_unplumb(ip_cache_t *);
1957c478bd9Sstevel@tonic-gate static int	if_replumb(ip_cache_t *);
1967c478bd9Sstevel@tonic-gate static void 	ip_log_err(ip_cache_t *, char **, char *);
197d62bc4baSyz147064 static char	*get_link_resource(const char *);
1987c478bd9Sstevel@tonic-gate static void	clr_cfg_state(ip_pif_t *);
1997c478bd9Sstevel@tonic-gate static int	modop(char *, char *, int, char);
2007c478bd9Sstevel@tonic-gate static int	get_modlist(char *, ip_lif_t *);
201fc80c0dfSnordmark static int	ip_domux2fd(int *, int *, int *, struct lifreq *);
202fc80c0dfSnordmark static int	ip_plink(int, int, int, struct lifreq *);
2037c478bd9Sstevel@tonic-gate static int	ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
2047c478bd9Sstevel@tonic-gate 			rcm_info_t **);
2057c478bd9Sstevel@tonic-gate static int	ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
2067c478bd9Sstevel@tonic-gate 			rcm_info_t **);
2077c478bd9Sstevel@tonic-gate static char 	**ip_get_addrlist(ip_cache_t *);
2087c478bd9Sstevel@tonic-gate static void	ip_free_addrlist(char **);
209d62bc4baSyz147064 static void	ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **,
210d62bc4baSyz147064 			uint_t, rcm_info_t **);
211e11c3f44Smeem static boolean_t ip_addrstr(ip_lif_t *, char *, size_t);
2127c478bd9Sstevel@tonic-gate 
2136e91bba0SGirish Moodalbail static int if_configure_hostname(datalink_id_t);
2146e91bba0SGirish Moodalbail static int if_configure_ipadm(datalink_id_t);
2156e91bba0SGirish Moodalbail static boolean_t if_hostname_exists(char *, sa_family_t);
216e11c3f44Smeem static boolean_t isgrouped(const char *);
217e11c3f44Smeem static int if_config_inst(const char *, FILE *, int, boolean_t);
218e11c3f44Smeem static uint_t ntok(const char *cp);
219e11c3f44Smeem static boolean_t ifconfig(const char *, const char *, const char *, boolean_t);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate /* Module-Private data */
2227c478bd9Sstevel@tonic-gate static struct rcm_mod_ops ip_ops =
2237c478bd9Sstevel@tonic-gate {
2247c478bd9Sstevel@tonic-gate 	RCM_MOD_OPS_VERSION,
2257c478bd9Sstevel@tonic-gate 	ip_register,
2267c478bd9Sstevel@tonic-gate 	ip_unregister,
2277c478bd9Sstevel@tonic-gate 	ip_get_info,
2287c478bd9Sstevel@tonic-gate 	ip_suspend,
2297c478bd9Sstevel@tonic-gate 	ip_resume,
2307c478bd9Sstevel@tonic-gate 	ip_offline,
2317c478bd9Sstevel@tonic-gate 	ip_undo_offline,
2327c478bd9Sstevel@tonic-gate 	ip_remove,
2337c478bd9Sstevel@tonic-gate 	NULL,
2347c478bd9Sstevel@tonic-gate 	NULL,
2357c478bd9Sstevel@tonic-gate 	ip_notify_event
2367c478bd9Sstevel@tonic-gate };
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate /*
2397c478bd9Sstevel@tonic-gate  * rcm_mod_init() - Update registrations, and return the ops structure.
2407c478bd9Sstevel@tonic-gate  */
2417c478bd9Sstevel@tonic-gate struct rcm_mod_ops *
2427c478bd9Sstevel@tonic-gate rcm_mod_init(void)
2437c478bd9Sstevel@tonic-gate {
244d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	char errmsg[DLADM_STRSIZE];
245d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	dladm_status_t status;
2466e91bba0SGirish Moodalbail 	ipadm_status_t iph_status;
247d4d1f7bfSVasumathi Sundaram - Sun Microsystems 
2487c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: mod_init\n");
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	cache_head.ip_next = &cache_tail;
2517c478bd9Sstevel@tonic-gate 	cache_head.ip_prev = NULL;
2527c478bd9Sstevel@tonic-gate 	cache_tail.ip_prev = &cache_head;
2537c478bd9Sstevel@tonic-gate 	cache_tail.ip_next = NULL;
2547c478bd9Sstevel@tonic-gate 	(void) mutex_init(&cache_lock, NULL, NULL);
2557c478bd9Sstevel@tonic-gate 
256d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
257d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		rcm_log_message(RCM_WARNING,
258d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		    "IP: mod_init failed: cannot get datalink handle: %s\n",
259d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		    dladm_status2str(status, errmsg));
260d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		return (NULL);
261d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	}
2624ac67f02SAnurag S. Maskey 
2636e91bba0SGirish Moodalbail 	if ((iph_status = ipadm_open(&ip_handle, 0)) != IPADM_SUCCESS) {
2646e91bba0SGirish Moodalbail 		rcm_log_message(RCM_ERROR,
2656e91bba0SGirish Moodalbail 		    "IP: mod_init failed: cannot get IP handle: %s\n",
2666e91bba0SGirish Moodalbail 		    ipadm_status2str(iph_status));
2676e91bba0SGirish Moodalbail 		dladm_close(dld_handle);
2686e91bba0SGirish Moodalbail 		dld_handle = NULL;
2696e91bba0SGirish Moodalbail 		return (NULL);
2706e91bba0SGirish Moodalbail 	}
2716e91bba0SGirish Moodalbail 
2727c478bd9Sstevel@tonic-gate 	/* Return the ops vectors */
2737c478bd9Sstevel@tonic-gate 	return (&ip_ops);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate  * rcm_mod_info() - Return a string describing this module.
2787c478bd9Sstevel@tonic-gate  */
2797c478bd9Sstevel@tonic-gate const char *
2807c478bd9Sstevel@tonic-gate rcm_mod_info(void)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: mod_info\n");
2837c478bd9Sstevel@tonic-gate 
284648495d6Svikram 	return ("IP Multipathing module version 1.23");
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate /*
2887c478bd9Sstevel@tonic-gate  * rcm_mod_fini() - Destroy the network interfaces cache.
2897c478bd9Sstevel@tonic-gate  */
2907c478bd9Sstevel@tonic-gate int
2917c478bd9Sstevel@tonic-gate rcm_mod_fini(void)
2927c478bd9Sstevel@tonic-gate {
2937c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: mod_fini\n");
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	free_cache();
2967c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&cache_lock);
2974ac67f02SAnurag S. Maskey 
2984ac67f02SAnurag S. Maskey 	dladm_close(dld_handle);
2996e91bba0SGirish Moodalbail 	ipadm_close(ip_handle);
3007c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
3017c478bd9Sstevel@tonic-gate }
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /*
3047c478bd9Sstevel@tonic-gate  * ip_register() - Make sure the cache is properly sync'ed, and its
3057c478bd9Sstevel@tonic-gate  *		 registrations are in order.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate static int
3087c478bd9Sstevel@tonic-gate ip_register(rcm_handle_t *hd)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: register\n");
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
3137c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (update_cache(hd) < 0)
3167c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	/*
3197c478bd9Sstevel@tonic-gate 	 * Need to register interest in all new resources
3207c478bd9Sstevel@tonic-gate 	 * getting attached, so we get attach event notifications
3217c478bd9Sstevel@tonic-gate 	 */
3227c478bd9Sstevel@tonic-gate 	if (!events_registered) {
323d62bc4baSyz147064 		if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
3247c478bd9Sstevel@tonic-gate 		    != RCM_SUCCESS) {
3257c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
3267c478bd9Sstevel@tonic-gate 			    _("IP: failed to register %s\n"),
327d62bc4baSyz147064 			    RCM_RESOURCE_LINK_NEW);
3287c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
3297c478bd9Sstevel@tonic-gate 		} else {
3307c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
331d62bc4baSyz147064 			    RCM_RESOURCE_LINK_NEW);
3327c478bd9Sstevel@tonic-gate 			events_registered++;
3337c478bd9Sstevel@tonic-gate 		}
3347c478bd9Sstevel@tonic-gate 	}
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate  * ip_unregister() - Walk the cache, unregistering all the networks.
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate static int
3437c478bd9Sstevel@tonic-gate ip_unregister(rcm_handle_t *hd)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	ip_cache_t *probe;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: unregister\n");
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
3507c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	/* Walk the cache, unregistering everything */
3537c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
3547c478bd9Sstevel@tonic-gate 	probe = cache_head.ip_next;
3557c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
3567c478bd9Sstevel@tonic-gate 		if (rcm_unregister_interest(hd, probe->ip_resource, 0)
3577c478bd9Sstevel@tonic-gate 		    != RCM_SUCCESS) {
3587c478bd9Sstevel@tonic-gate 			/* unregister failed for whatever reason */
3597c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
3607c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
3617c478bd9Sstevel@tonic-gate 		}
3627c478bd9Sstevel@tonic-gate 		cache_remove(probe);
3637c478bd9Sstevel@tonic-gate 		free_node(probe);
3647c478bd9Sstevel@tonic-gate 		probe = cache_head.ip_next;
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	/*
3697c478bd9Sstevel@tonic-gate 	 * Need to unregister interest in all new resources
3707c478bd9Sstevel@tonic-gate 	 */
3717c478bd9Sstevel@tonic-gate 	if (events_registered) {
372d62bc4baSyz147064 		if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
3737c478bd9Sstevel@tonic-gate 		    != RCM_SUCCESS) {
3747c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
3757c478bd9Sstevel@tonic-gate 			    _("IP: failed to unregister %s\n"),
376d62bc4baSyz147064 			    RCM_RESOURCE_LINK_NEW);
3777c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
3787c478bd9Sstevel@tonic-gate 		} else {
3797c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
380d62bc4baSyz147064 			    RCM_RESOURCE_LINK_NEW);
3817c478bd9Sstevel@tonic-gate 			events_registered--;
3827c478bd9Sstevel@tonic-gate 		}
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate /*
3897c478bd9Sstevel@tonic-gate  * ip_offline() - Offline an interface.
3907c478bd9Sstevel@tonic-gate  */
3917c478bd9Sstevel@tonic-gate static int
3927c478bd9Sstevel@tonic-gate ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
3937c478bd9Sstevel@tonic-gate     char **errorp, rcm_info_t **depend_info)
3947c478bd9Sstevel@tonic-gate {
3957c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
3967c478bd9Sstevel@tonic-gate 	ip_pif_t *pif;
397e11c3f44Smeem 	boolean_t detachable = B_FALSE;
398e11c3f44Smeem 	boolean_t ipmp;
399e11c3f44Smeem 	int retval;
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc);
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
4047c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
4057c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
4067c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
4077c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
4087c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	/* Lock the cache and lookup the resource */
4117c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
4127c478bd9Sstevel@tonic-gate 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
4137c478bd9Sstevel@tonic-gate 	if (node == NULL) {
4147c478bd9Sstevel@tonic-gate 		ip_log_err(node, errorp, "Unrecognized resource");
4157c478bd9Sstevel@tonic-gate 		errno = ENOENT;
4167c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
4177c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
4187c478bd9Sstevel@tonic-gate 	}
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 	pif = node->ip_pif;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	/* Establish default detachability criteria */
423e11c3f44Smeem 	if (flags & RCM_FORCE)
424e11c3f44Smeem 		detachable = B_TRUE;
4257c478bd9Sstevel@tonic-gate 
426e11c3f44Smeem 	/* Check if the interface is under IPMP */
427e11c3f44Smeem 	ipmp = (pif->pi_grname[0] != '\0');
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate 	/*
430e11c3f44Smeem 	 * Even if the interface is not under IPMP, it's possible that it's
431e11c3f44Smeem 	 * still okay to offline it as long as there are higher-level failover
432e11c3f44Smeem 	 * mechanisms for the addresses it owns (e.g., clustering).  In this
433e11c3f44Smeem 	 * case, ip_offlinelist() will return RCM_SUCCESS, and we charge on.
4347c478bd9Sstevel@tonic-gate 	 */
4357c478bd9Sstevel@tonic-gate 	if (!ipmp && !detachable) {
4367c478bd9Sstevel@tonic-gate 		/* Inform consumers of IP addresses being offlined */
4377c478bd9Sstevel@tonic-gate 		if (ip_offlinelist(hd, node, errorp, flags, depend_info) ==
4387c478bd9Sstevel@tonic-gate 		    RCM_SUCCESS) {
4397c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
4407c478bd9Sstevel@tonic-gate 			    "IP: consumers agree on detach");
4417c478bd9Sstevel@tonic-gate 		} else {
4427c478bd9Sstevel@tonic-gate 			ip_log_err(node, errorp,
4437c478bd9Sstevel@tonic-gate 			    "Device consumers prohibit offline");
4447c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
4457c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
4467c478bd9Sstevel@tonic-gate 		}
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	/* Check if it's a query */
4507c478bd9Sstevel@tonic-gate 	if (flags & RCM_QUERY) {
4517c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n",
4527c478bd9Sstevel@tonic-gate 		    rsrc);
4537c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
4547c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	/* Check detachability, save configuration if detachable */
4587c478bd9Sstevel@tonic-gate 	if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) {
4597c478bd9Sstevel@tonic-gate 		node->ip_cachestate |= CACHE_IF_IGNORE;
4607c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc);
4617c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
4627c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
4637c478bd9Sstevel@tonic-gate 	}
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	/* standalone detachable device */
4667c478bd9Sstevel@tonic-gate 	if (!ipmp) {
4677c478bd9Sstevel@tonic-gate 		if (if_unplumb(node) < 0) {
4687c478bd9Sstevel@tonic-gate 			ip_log_err(node, errorp,
4697c478bd9Sstevel@tonic-gate 			    "Failed to unplumb the device");
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 			errno = EIO;
4727c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
4737c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
4747c478bd9Sstevel@tonic-gate 		}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 		node->ip_cachestate |= CACHE_IF_OFFLINED;
4777c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc);
4787c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
4797c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	/*
483e11c3f44Smeem 	 * This is an IPMP interface that can be offlined.
484e11c3f44Smeem 	 * Request in.mpathd(1M) to offline the physical interface.
4857c478bd9Sstevel@tonic-gate 	 */
486e11c3f44Smeem 	if ((retval = ip_ipmp_offline(node)) != IPMP_SUCCESS)
487e11c3f44Smeem 		ip_log_err(node, errorp, "in.mpathd offline failed");
4887c478bd9Sstevel@tonic-gate 
489e11c3f44Smeem 	if (retval == IPMP_EMINRED && !detachable) {
4907c478bd9Sstevel@tonic-gate 		/*
491e11c3f44Smeem 		 * in.mpathd(1M) could not offline the device because it was
492e11c3f44Smeem 		 * the last interface in the group.  However, it's possible
493e11c3f44Smeem 		 * that it's still okay to offline it as long as there are
494e11c3f44Smeem 		 * higher-level failover mechanisms for the addresses it owns
495e11c3f44Smeem 		 * (e.g., clustering).  In this case, ip_offlinelist() will
496e11c3f44Smeem 		 * return RCM_SUCCESS, and we charge on.
4977c478bd9Sstevel@tonic-gate 		 */
4987c478bd9Sstevel@tonic-gate 		/* Inform consumers of IP addresses being offlined */
4997c478bd9Sstevel@tonic-gate 		if (ip_offlinelist(hd, node, errorp, flags,
5007c478bd9Sstevel@tonic-gate 		    depend_info) == RCM_SUCCESS) {
5017c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
5027c478bd9Sstevel@tonic-gate 			    "IP: consumers agree on detach");
5037c478bd9Sstevel@tonic-gate 		} else {
5047c478bd9Sstevel@tonic-gate 			ip_log_err(node, errorp,
5057c478bd9Sstevel@tonic-gate 			    "Device consumers prohibit offline");
5067c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
5077c478bd9Sstevel@tonic-gate 			errno = EBUSY;
5087c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
5097c478bd9Sstevel@tonic-gate 		}
5107c478bd9Sstevel@tonic-gate 	}
5117c478bd9Sstevel@tonic-gate 
5127c478bd9Sstevel@tonic-gate 	if (if_unplumb(node) < 0) {
5137c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
5147c478bd9Sstevel@tonic-gate 		    _("IP: Unplumb failed (%s)\n"),
5157c478bd9Sstevel@tonic-gate 		    pif->pi_ifname);
5167c478bd9Sstevel@tonic-gate 
517e11c3f44Smeem 		/* Request in.mpathd to undo the offline */
518e11c3f44Smeem 		if (ip_ipmp_undo_offline(node) != IPMP_SUCCESS) {
5197c478bd9Sstevel@tonic-gate 			ip_log_err(node, errorp, "Undo offline failed");
5207c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
5217c478bd9Sstevel@tonic-gate 			return (RCM_FAILURE);
5227c478bd9Sstevel@tonic-gate 		}
5237c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
5247c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	node->ip_cachestate |= CACHE_IF_OFFLINED;
5287c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc);
5297c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
5307c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate /*
5347c478bd9Sstevel@tonic-gate  * ip_undo_offline() - Undo offline of a previously offlined device.
5357c478bd9Sstevel@tonic-gate  */
5367c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5377c478bd9Sstevel@tonic-gate static int
5387c478bd9Sstevel@tonic-gate ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
5397c478bd9Sstevel@tonic-gate     char **errorp, rcm_info_t **depend_info)
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc);
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
5467c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
5477c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
5487c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
5497c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
5507c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
5537c478bd9Sstevel@tonic-gate 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	if (node == NULL) {
5567c478bd9Sstevel@tonic-gate 		ip_log_err(node, errorp, "No such device");
5577c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
5587c478bd9Sstevel@tonic-gate 		errno = ENOENT;
5597c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	/* Check if no attempt should be made to online the device here */
5637c478bd9Sstevel@tonic-gate 	if (node->ip_cachestate & CACHE_IF_IGNORE) {
5647c478bd9Sstevel@tonic-gate 		node->ip_cachestate &= ~(CACHE_IF_IGNORE);
5657c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
5667c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
5677c478bd9Sstevel@tonic-gate 	}
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	/* Check if the interface was previously offlined */
5707c478bd9Sstevel@tonic-gate 	if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) {
5717c478bd9Sstevel@tonic-gate 		ip_log_err(node, errorp, "Device not offlined");
5727c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
5737c478bd9Sstevel@tonic-gate 		errno = ENOTSUP;
5747c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
5757c478bd9Sstevel@tonic-gate 	}
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	if (if_replumb(node) == -1) {
5787c478bd9Sstevel@tonic-gate 		/* re-plumb failed */
5797c478bd9Sstevel@tonic-gate 		ip_log_err(node, errorp, "Replumb failed");
5807c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
5817c478bd9Sstevel@tonic-gate 		errno = EIO;
5827c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	/* Inform consumers about IP addresses being un-offlined */
5877c478bd9Sstevel@tonic-gate 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	node->ip_cachestate &= ~(CACHE_IF_OFFLINED);
5907c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc);
5917c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
5927c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate  * ip_get_info() - Gather usage information for this resource.
5977c478bd9Sstevel@tonic-gate  */
5987c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5997c478bd9Sstevel@tonic-gate int
6007c478bd9Sstevel@tonic-gate ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
6017c478bd9Sstevel@tonic-gate     char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info)
6027c478bd9Sstevel@tonic-gate {
6037c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
6047c478bd9Sstevel@tonic-gate 	char *infostr;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
6077c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
6087c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
6097c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
6107c478bd9Sstevel@tonic-gate 	assert(usagep != NULL);
6117c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
6127c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc);
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
6177c478bd9Sstevel@tonic-gate 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
6187c478bd9Sstevel@tonic-gate 	if (!node) {
6197c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_INFO,
6207c478bd9Sstevel@tonic-gate 		    _("IP: get_info(%s) unrecognized resource\n"), rsrc);
6217c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
6227c478bd9Sstevel@tonic-gate 		errno = ENOENT;
6237c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
6247c478bd9Sstevel@tonic-gate 	}
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	infostr = ip_usage(node);
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	if (infostr == NULL) {
6297c478bd9Sstevel@tonic-gate 		/* most likely malloc failure */
6307c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
6317c478bd9Sstevel@tonic-gate 		    _("IP: get_info(%s) malloc failure\n"), rsrc);
6327c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
6337c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
6347c478bd9Sstevel@tonic-gate 		*errorp = NULL;
6357c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
6367c478bd9Sstevel@tonic-gate 	}
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	/* Set client/role properties */
6397c478bd9Sstevel@tonic-gate 	(void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP");
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	/* Set usage property, infostr will be freed by caller */
6427c478bd9Sstevel@tonic-gate 	*usagep = infostr;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n",
6457c478bd9Sstevel@tonic-gate 	    rsrc, infostr);
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
6487c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate /*
6527c478bd9Sstevel@tonic-gate  * ip_suspend() - Nothing to do, always okay
6537c478bd9Sstevel@tonic-gate  */
6547c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6557c478bd9Sstevel@tonic-gate static int
6567c478bd9Sstevel@tonic-gate ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
6577c478bd9Sstevel@tonic-gate 			uint_t flags, char **errorp, rcm_info_t **depend_info)
6587c478bd9Sstevel@tonic-gate {
6597c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
6607c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
6617c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
6627c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
6637c478bd9Sstevel@tonic-gate 	assert(interval != NULL);
6647c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
6657c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc);
6687c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate /*
6727c478bd9Sstevel@tonic-gate  * ip_resume() - Nothing to do, always okay
6737c478bd9Sstevel@tonic-gate  */
6747c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6757c478bd9Sstevel@tonic-gate static int
6767c478bd9Sstevel@tonic-gate ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
6777c478bd9Sstevel@tonic-gate 		char **errorp, rcm_info_t ** depend_info)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
6807c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
6817c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
6827c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
6837c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
6847c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc);
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
6897c478bd9Sstevel@tonic-gate }
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate /*
6927c478bd9Sstevel@tonic-gate  * ip_remove() - remove a resource from cache
6937c478bd9Sstevel@tonic-gate  */
6947c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6957c478bd9Sstevel@tonic-gate static int
6967c478bd9Sstevel@tonic-gate ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
6977c478bd9Sstevel@tonic-gate 		char **errorp, rcm_info_t **depend_info)
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	/* Guard against bad arguments */
7027c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
7037c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
7047c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
7057c478bd9Sstevel@tonic-gate 	assert(errorp != NULL);
7067c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
7117c478bd9Sstevel@tonic-gate 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
7127c478bd9Sstevel@tonic-gate 	if (!node) {
7137c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_INFO,
7147c478bd9Sstevel@tonic-gate 		    _("IP: remove(%s) unrecognized resource\n"), rsrc);
7157c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
7167c478bd9Sstevel@tonic-gate 		errno = ENOENT;
7177c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	/* remove the cached entry for the resource */
7217c478bd9Sstevel@tonic-gate 	cache_remove(node);
722392b1d6eSyz147064 	free_node(node);
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
7257c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate  * ip_notify_event - Project private implementation to receive new resource
7307c478bd9Sstevel@tonic-gate  *		   events. It intercepts all new resource events. If the
7317c478bd9Sstevel@tonic-gate  *		   new resource is a network resource, pass up a notify
7327c478bd9Sstevel@tonic-gate  *		   for it too. The new resource need not be cached, since
7337c478bd9Sstevel@tonic-gate  *		   it is done at register again.
7347c478bd9Sstevel@tonic-gate  */
7357c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7367c478bd9Sstevel@tonic-gate static int
7377c478bd9Sstevel@tonic-gate ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
7387c478bd9Sstevel@tonic-gate 			char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
7397c478bd9Sstevel@tonic-gate {
740d62bc4baSyz147064 	datalink_id_t	linkid;
741d62bc4baSyz147064 	nvpair_t *nvp = NULL;
742d62bc4baSyz147064 	uint64_t id64;
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
7457c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
7467c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
7477c478bd9Sstevel@tonic-gate 	assert(nvl != NULL);
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc);
7507c478bd9Sstevel@tonic-gate 
751d62bc4baSyz147064 	if (!STREQ(rsrc, RCM_RESOURCE_LINK_NEW)) {
7527c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_INFO,
7537c478bd9Sstevel@tonic-gate 		    _("IP: unrecognized event for %s\n"), rsrc);
7547c478bd9Sstevel@tonic-gate 		ip_log_err(NULL, errorp, "unrecognized event");
7557c478bd9Sstevel@tonic-gate 		errno = EINVAL;
7567c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	/* Update cache to reflect latest interfaces */
7607c478bd9Sstevel@tonic-gate 	if (update_cache(hd) < 0) {
7617c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n"));
7627c478bd9Sstevel@tonic-gate 		ip_log_err(NULL, errorp, "Private Cache update failed");
7637c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
7647c478bd9Sstevel@tonic-gate 	}
7657c478bd9Sstevel@tonic-gate 
766d62bc4baSyz147064 	rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n");
767d62bc4baSyz147064 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
768d62bc4baSyz147064 		if (STREQ(nvpair_name(nvp), RCM_NV_LINKID)) {
769d62bc4baSyz147064 			if (nvpair_value_uint64(nvp, &id64) != 0) {
7707c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_WARNING,
771d62bc4baSyz147064 				    _("IP: cannot get linkid\n"));
772d62bc4baSyz147064 				return (RCM_FAILURE);
7737c478bd9Sstevel@tonic-gate 			}
774d62bc4baSyz147064 			linkid = (datalink_id_t)id64;
7756e91bba0SGirish Moodalbail 			/*
7766e91bba0SGirish Moodalbail 			 * Grovel through /etc/hostname* files and configure
7776e91bba0SGirish Moodalbail 			 * interface in the same way that they would be handled
7786e91bba0SGirish Moodalbail 			 * by network/physical.
7796e91bba0SGirish Moodalbail 			 */
7806e91bba0SGirish Moodalbail 			if (if_configure_hostname(linkid) != 0) {
7816e91bba0SGirish Moodalbail 				rcm_log_message(RCM_ERROR,
7826e91bba0SGirish Moodalbail 				    _("IP: Configuration failed (%u)\n"),
7836e91bba0SGirish Moodalbail 				    linkid);
7846e91bba0SGirish Moodalbail 				ip_log_err(NULL, errorp,
7856e91bba0SGirish Moodalbail 				    "Failed configuring one or more IP "
7866e91bba0SGirish Moodalbail 				    "addresses");
7876e91bba0SGirish Moodalbail 			}
7886e91bba0SGirish Moodalbail 
7896e91bba0SGirish Moodalbail 			/*
7906e91bba0SGirish Moodalbail 			 * Query libipadm for persistent configuration info
7916e91bba0SGirish Moodalbail 			 * and resurrect that persistent configuration.
7926e91bba0SGirish Moodalbail 			 */
7936e91bba0SGirish Moodalbail 			if (if_configure_ipadm(linkid) != 0) {
7947c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_ERROR,
795d62bc4baSyz147064 				    _("IP: Configuration failed (%u)\n"),
796d62bc4baSyz147064 				    linkid);
7977c478bd9Sstevel@tonic-gate 				ip_log_err(NULL, errorp,
798d62bc4baSyz147064 				    "Failed configuring one or more IP "
799d62bc4baSyz147064 				    "addresses");
8007c478bd9Sstevel@tonic-gate 			}
8017c478bd9Sstevel@tonic-gate 
802d62bc4baSyz147064 			/* Notify all IP address consumers */
803d62bc4baSyz147064 			ip_consumer_notify(hd, linkid, errorp, flags,
8047c478bd9Sstevel@tonic-gate 			    depend_info);
8057c478bd9Sstevel@tonic-gate 		}
8067c478bd9Sstevel@tonic-gate 	}
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1,
8097c478bd9Sstevel@tonic-gate 	    "IP: notify_event: device configuration complete\n");
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate /*
8157c478bd9Sstevel@tonic-gate  * ip_usage - Determine the usage of a device.  Call with cache_lock held.
8167c478bd9Sstevel@tonic-gate  *	    The returned buffer is owned by caller, and the caller
8177c478bd9Sstevel@tonic-gate  *	    must free it up when done.
8187c478bd9Sstevel@tonic-gate  */
8197c478bd9Sstevel@tonic-gate static char *
8207c478bd9Sstevel@tonic-gate ip_usage(ip_cache_t *node)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
823e11c3f44Smeem 	uint_t numup;
824e11c3f44Smeem 	char *sep, *buf, *linkidstr;
825d62bc4baSyz147064 	datalink_id_t linkid;
826e11c3f44Smeem 	const char *msg;
827d62bc4baSyz147064 	char link[MAXLINKNAMELEN];
8287c478bd9Sstevel@tonic-gate 	char addrstr[INET6_ADDRSTRLEN];
829d62bc4baSyz147064 	char errmsg[DLADM_STRSIZE];
830d62bc4baSyz147064 	dladm_status_t status;
831e11c3f44Smeem 	boolean_t offline, ipmp;
832e11c3f44Smeem 	size_t bufsz = 0;
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource);
8357c478bd9Sstevel@tonic-gate 
836d62bc4baSyz147064 	/*
837d62bc4baSyz147064 	 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid>
838d62bc4baSyz147064 	 */
839d62bc4baSyz147064 	linkidstr = strchr(node->ip_resource, '/');
840d62bc4baSyz147064 	assert(linkidstr != NULL);
841d62bc4baSyz147064 	linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource;
842d62bc4baSyz147064 
843d62bc4baSyz147064 	errno = 0;
844d62bc4baSyz147064 	linkid = strtol(linkidstr, &buf, 10);
845d62bc4baSyz147064 	if (errno != 0 || *buf != '\0') {
846d62bc4baSyz147064 		rcm_log_message(RCM_ERROR,
847d62bc4baSyz147064 		    _("IP: usage(%s) parse linkid failure (%s)\n"),
848d62bc4baSyz147064 		    node->ip_resource, strerror(errno));
849d62bc4baSyz147064 		return (NULL);
850d62bc4baSyz147064 	}
851d62bc4baSyz147064 
8524ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL, NULL,
8534ac67f02SAnurag S. Maskey 	    NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
854d62bc4baSyz147064 		rcm_log_message(RCM_ERROR,
855d62bc4baSyz147064 		    _("IP: usage(%s) get link name failure(%s)\n"),
856d62bc4baSyz147064 		    node->ip_resource, dladm_status2str(status, errmsg));
857d62bc4baSyz147064 		return (NULL);
858d62bc4baSyz147064 	}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	/* TRANSLATION_NOTE: separator used between IP addresses */
8617c478bd9Sstevel@tonic-gate 	sep = _(", ");
8627c478bd9Sstevel@tonic-gate 
863e11c3f44Smeem 	numup = 0;
864e11c3f44Smeem 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next)
865e11c3f44Smeem 		if (lif->li_ifflags & IFF_UP)
866e11c3f44Smeem 			numup++;
8677c478bd9Sstevel@tonic-gate 
868e11c3f44Smeem 	ipmp = (node->ip_pif->pi_grname[0] != '\0');
869e11c3f44Smeem 	offline = ((node->ip_cachestate & CACHE_IF_OFFLINED) != 0);
8707c478bd9Sstevel@tonic-gate 
871e11c3f44Smeem 	if (offline) {
872e11c3f44Smeem 		msg = _("offlined");
873e11c3f44Smeem 	} else if (numup == 0) {
874e11c3f44Smeem 		msg = _("plumbed but down");
8757c478bd9Sstevel@tonic-gate 	} else {
876e11c3f44Smeem 		if (ipmp) {
877e11c3f44Smeem 			msg = _("providing connectivity for IPMP group ");
878e11c3f44Smeem 			bufsz += LIFGRNAMSIZ;
879e11c3f44Smeem 		} else {
880e11c3f44Smeem 			msg = _("hosts IP addresses: ");
881e11c3f44Smeem 			bufsz += (numup * (INET6_ADDRSTRLEN + strlen(sep)));
882e11c3f44Smeem 		}
8837c478bd9Sstevel@tonic-gate 	}
8847c478bd9Sstevel@tonic-gate 
885e11c3f44Smeem 	bufsz += strlen(link) + strlen(msg) + 1;
8867c478bd9Sstevel@tonic-gate 	if ((buf = malloc(bufsz)) == NULL) {
8877c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
8887c478bd9Sstevel@tonic-gate 		    _("IP: usage(%s) malloc failure(%s)\n"),
8897c478bd9Sstevel@tonic-gate 		    node->ip_resource, strerror(errno));
8907c478bd9Sstevel@tonic-gate 		return (NULL);
8917c478bd9Sstevel@tonic-gate 	}
892e11c3f44Smeem 	(void) snprintf(buf, bufsz, "%s: %s", link, msg);
8937c478bd9Sstevel@tonic-gate 
894e11c3f44Smeem 	if (!offline && numup > 0) {
895e11c3f44Smeem 		if (ipmp) {
896e11c3f44Smeem 			(void) strlcat(buf, node->ip_pif->pi_grname, bufsz);
897e11c3f44Smeem 		} else {
898e11c3f44Smeem 			lif = node->ip_pif->pi_lifs;
899e11c3f44Smeem 			for (; lif != NULL; lif = lif->li_next) {
900e11c3f44Smeem 				if (!(lif->li_ifflags & IFF_UP))
901e11c3f44Smeem 					continue;
902e11c3f44Smeem 
903e11c3f44Smeem 				if (!ip_addrstr(lif, addrstr, sizeof (addrstr)))
904e11c3f44Smeem 					continue;
905e11c3f44Smeem 
906e11c3f44Smeem 				(void) strlcat(buf, addrstr, bufsz);
907e11c3f44Smeem 				if (--numup > 0)
908e11c3f44Smeem 					(void) strlcat(buf, sep, bufsz);
909e11c3f44Smeem 			}
910e11c3f44Smeem 		}
911e11c3f44Smeem 	}
912e11c3f44Smeem 
9137c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
9147c478bd9Sstevel@tonic-gate 	    node->ip_resource, buf);
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate 	return (buf);
9177c478bd9Sstevel@tonic-gate }
9187c478bd9Sstevel@tonic-gate 
919e11c3f44Smeem static boolean_t
920e11c3f44Smeem ip_addrstr(ip_lif_t *lif, char *addrstr, size_t addrsize)
921e11c3f44Smeem {
922e11c3f44Smeem 	int af = lif->li_addr.family;
9237c478bd9Sstevel@tonic-gate 	void *addr;
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	if (af == AF_INET6) {
9267c478bd9Sstevel@tonic-gate 		addr = &lif->li_addr.ip6.sin6_addr;
9277c478bd9Sstevel@tonic-gate 	} else if (af == AF_INET) {
9287c478bd9Sstevel@tonic-gate 		addr = &lif->li_addr.ip4.sin_addr;
9297c478bd9Sstevel@tonic-gate 	} else {
9307c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG,
931e11c3f44Smeem 		    "IP: unknown addr family %d, assuming AF_INET\n", af);
9327c478bd9Sstevel@tonic-gate 		af = AF_INET;
9337c478bd9Sstevel@tonic-gate 		addr = &lif->li_addr.ip4.sin_addr;
9347c478bd9Sstevel@tonic-gate 	}
935e11c3f44Smeem 	if (inet_ntop(af, addr, addrstr, addrsize) == NULL) {
9367c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
9377c478bd9Sstevel@tonic-gate 		    _("IP: inet_ntop: %s\n"), strerror(errno));
938e11c3f44Smeem 		return (B_FALSE);
9397c478bd9Sstevel@tonic-gate 	}
940e11c3f44Smeem 
9417c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr);
942e11c3f44Smeem 	return (B_TRUE);
9437c478bd9Sstevel@tonic-gate }
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate /*
9467c478bd9Sstevel@tonic-gate  * Cache management routines, all cache management functions should be
9477c478bd9Sstevel@tonic-gate  * be called with cache_lock held.
9487c478bd9Sstevel@tonic-gate  */
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate /*
951d62bc4baSyz147064  * cache_lookup() - Get a cache node for a resource.
9527c478bd9Sstevel@tonic-gate  *		  Call with cache lock held.
9537c478bd9Sstevel@tonic-gate  *
9547c478bd9Sstevel@tonic-gate  * This ensures that the cache is consistent with the system state and
9557c478bd9Sstevel@tonic-gate  * returns a pointer to the cache element corresponding to the resource.
9567c478bd9Sstevel@tonic-gate  */
9577c478bd9Sstevel@tonic-gate static ip_cache_t *
9587c478bd9Sstevel@tonic-gate cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
9597c478bd9Sstevel@tonic-gate {
9607c478bd9Sstevel@tonic-gate 	ip_cache_t *probe;
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc);
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	if ((options & CACHE_REFRESH) && (hd != NULL)) {
9657c478bd9Sstevel@tonic-gate 		/* drop lock since update locks cache again */
9667c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
9677c478bd9Sstevel@tonic-gate 		(void) update_cache(hd);
9687c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&cache_lock);
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	probe = cache_head.ip_next;
9727c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
9737c478bd9Sstevel@tonic-gate 		if (probe->ip_resource &&
974d62bc4baSyz147064 		    STREQ(rsrc, probe->ip_resource)) {
9757c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE2,
9767c478bd9Sstevel@tonic-gate 			    "IP: cache lookup success(%s)\n", rsrc);
9777c478bd9Sstevel@tonic-gate 			return (probe);
9787c478bd9Sstevel@tonic-gate 		}
9797c478bd9Sstevel@tonic-gate 		probe = probe->ip_next;
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 	return (NULL);
9827c478bd9Sstevel@tonic-gate }
9837c478bd9Sstevel@tonic-gate 
9847c478bd9Sstevel@tonic-gate /*
9857c478bd9Sstevel@tonic-gate  * free_node - Free a node from the cache
9867c478bd9Sstevel@tonic-gate  *	     Call with cache_lock held.
9877c478bd9Sstevel@tonic-gate  */
9887c478bd9Sstevel@tonic-gate static void
9897c478bd9Sstevel@tonic-gate free_node(ip_cache_t *node)
9907c478bd9Sstevel@tonic-gate {
9917c478bd9Sstevel@tonic-gate 	ip_pif_t *pif;
9927c478bd9Sstevel@tonic-gate 	ip_lif_t *lif, *tmplif;
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	if (node) {
9957c478bd9Sstevel@tonic-gate 		if (node->ip_resource) {
9967c478bd9Sstevel@tonic-gate 			free(node->ip_resource);
9977c478bd9Sstevel@tonic-gate 		}
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 		/* free the pif */
10007c478bd9Sstevel@tonic-gate 		pif = node->ip_pif;
10017c478bd9Sstevel@tonic-gate 		if (pif) {
10027c478bd9Sstevel@tonic-gate 			/* free logical interfaces */
10037c478bd9Sstevel@tonic-gate 			lif = pif->pi_lifs;
10047c478bd9Sstevel@tonic-gate 			while (lif) {
10057c478bd9Sstevel@tonic-gate 				tmplif = lif->li_next;
10067c478bd9Sstevel@tonic-gate 				free(lif);
10077c478bd9Sstevel@tonic-gate 				lif = tmplif;
10087c478bd9Sstevel@tonic-gate 			}
10097c478bd9Sstevel@tonic-gate 			free(pif);
10107c478bd9Sstevel@tonic-gate 		}
10117c478bd9Sstevel@tonic-gate 		free(node);
10127c478bd9Sstevel@tonic-gate 	}
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate /*
10167c478bd9Sstevel@tonic-gate  * cache_insert - Insert a resource node in cache
10177c478bd9Sstevel@tonic-gate  *		Call with the cache_lock held.
10187c478bd9Sstevel@tonic-gate  */
10197c478bd9Sstevel@tonic-gate static void
10207c478bd9Sstevel@tonic-gate cache_insert(ip_cache_t *node)
10217c478bd9Sstevel@tonic-gate {
1022d62bc4baSyz147064 	rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n",
1023d62bc4baSyz147064 	    node->ip_resource);
1024d62bc4baSyz147064 
10257c478bd9Sstevel@tonic-gate 	/* insert at the head for best performance */
10267c478bd9Sstevel@tonic-gate 	node->ip_next = cache_head.ip_next;
10277c478bd9Sstevel@tonic-gate 	node->ip_prev = &cache_head;
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	node->ip_next->ip_prev = node;
10307c478bd9Sstevel@tonic-gate 	node->ip_prev->ip_next = node;
10317c478bd9Sstevel@tonic-gate }
10327c478bd9Sstevel@tonic-gate 
10337c478bd9Sstevel@tonic-gate /*
10347c478bd9Sstevel@tonic-gate  * cache_remove() - Remove a resource node from cache.
10357c478bd9Sstevel@tonic-gate  *		  Call with the cache_lock held.
10367c478bd9Sstevel@tonic-gate  */
10377c478bd9Sstevel@tonic-gate static void
10387c478bd9Sstevel@tonic-gate cache_remove(ip_cache_t *node)
10397c478bd9Sstevel@tonic-gate {
1040d62bc4baSyz147064 	rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n",
1041d62bc4baSyz147064 	    node->ip_resource);
1042d62bc4baSyz147064 
10437c478bd9Sstevel@tonic-gate 	node->ip_next->ip_prev = node->ip_prev;
10447c478bd9Sstevel@tonic-gate 	node->ip_prev->ip_next = node->ip_next;
10457c478bd9Sstevel@tonic-gate 	node->ip_next = NULL;
10467c478bd9Sstevel@tonic-gate 	node->ip_prev = NULL;
10477c478bd9Sstevel@tonic-gate }
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate /*
10507c478bd9Sstevel@tonic-gate  * update_pif() - Update physical interface properties
10517c478bd9Sstevel@tonic-gate  *		Call with cache_lock held
10527c478bd9Sstevel@tonic-gate  */
10536e91bba0SGirish Moodalbail int
10546e91bba0SGirish Moodalbail update_pif(rcm_handle_t *hd, int af, int sock, struct ifaddrs *ifa)
10557c478bd9Sstevel@tonic-gate {
1056d62bc4baSyz147064 	char *rsrc;
1057595aa6e4Smeem 	ifspec_t ifspec;
10587c478bd9Sstevel@tonic-gate 	ushort_t ifnumber = 0;
10597c478bd9Sstevel@tonic-gate 	ip_cache_t *probe;
10607c478bd9Sstevel@tonic-gate 	ip_pif_t pif;
10617c478bd9Sstevel@tonic-gate 	ip_pif_t *probepif;
10627c478bd9Sstevel@tonic-gate 	ip_lif_t *probelif;
10637c478bd9Sstevel@tonic-gate 	struct lifreq lifreq;
10647c478bd9Sstevel@tonic-gate 	struct sockaddr_storage ifaddr;
10657c478bd9Sstevel@tonic-gate 	uint64_t ifflags;
10667c478bd9Sstevel@tonic-gate 	int lif_listed = 0;
10677c478bd9Sstevel@tonic-gate 
10686e91bba0SGirish Moodalbail 	rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", ifa->ifa_name);
10697c478bd9Sstevel@tonic-gate 
10706e91bba0SGirish Moodalbail 	if (!ifparse_ifspec(ifa->ifa_name, &ifspec)) {
1071595aa6e4Smeem 		rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"),
10726e91bba0SGirish Moodalbail 		    ifa->ifa_name);
10737c478bd9Sstevel@tonic-gate 		return (-1);
10747c478bd9Sstevel@tonic-gate 	}
10757c478bd9Sstevel@tonic-gate 
1076595aa6e4Smeem 	(void) snprintf(pif.pi_ifname, sizeof (pif.pi_ifname), "%s%d",
1077595aa6e4Smeem 	    ifspec.ifsp_devnm, ifspec.ifsp_ppa);
1078595aa6e4Smeem 	if (ifspec.ifsp_lunvalid)
1079595aa6e4Smeem 		ifnumber = ifspec.ifsp_lun;
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 	/* Get the interface flags */
10826e91bba0SGirish Moodalbail 	ifflags = ifa->ifa_flags;
10837c478bd9Sstevel@tonic-gate 
10848de9d095Syz147064 	/*
10858de9d095Syz147064 	 * Ignore interfaces that are always incapable of DR:
10868de9d095Syz147064 	 *   - IFF_VIRTUAL:	e.g., loopback and vni
10878de9d095Syz147064 	 *   - IFF_POINTOPOINT:	e.g., sppp and ip.tun
10888de9d095Syz147064 	 *   - !IFF_MULTICAST:	e.g., ip.6to4tun
1089e11c3f44Smeem 	 *   - IFF_IPMP:	IPMP meta-interfaces
10908de9d095Syz147064 	 *
10918de9d095Syz147064 	 * Note: The !IFF_MULTICAST check can be removed once iptun is
10928de9d095Syz147064 	 * implemented as a datalink.
10938de9d095Syz147064 	 */
10948de9d095Syz147064 	if (!(ifflags & IFF_MULTICAST) ||
1095e11c3f44Smeem 	    (ifflags & (IFF_POINTOPOINT | IFF_VIRTUAL | IFF_IPMP))) {
1096595aa6e4Smeem 		rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n",
1097595aa6e4Smeem 		    pif.pi_ifname);
10987c478bd9Sstevel@tonic-gate 		return (0);
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	/* Get the interface group name for this interface */
11026e91bba0SGirish Moodalbail 	bzero(&lifreq, sizeof (lifreq));
11036e91bba0SGirish Moodalbail 	(void) strncpy(lifreq.lifr_name, ifa->ifa_name, LIFNAMSIZ);
11046e91bba0SGirish Moodalbail 
11057c478bd9Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) {
1106e11c3f44Smeem 		if (errno != ENXIO) {
11077c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
11087c478bd9Sstevel@tonic-gate 			    _("IP: SIOCGLIFGROUPNAME(%s): %s\n"),
11097c478bd9Sstevel@tonic-gate 			    lifreq.lifr_name, strerror(errno));
1110e11c3f44Smeem 		}
11117c478bd9Sstevel@tonic-gate 		return (-1);
11127c478bd9Sstevel@tonic-gate 	}
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	/* copy the group name */
1115e11c3f44Smeem 	(void) strlcpy(pif.pi_grname, lifreq.lifr_groupname,
1116e11c3f44Smeem 	    sizeof (pif.pi_grname));
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	/* Get the interface address for this interface */
1119*64639aafSDarren Reed 	(void) memcpy(&ifaddr, ifa->ifa_addr, sizeof (ifaddr));
11207c478bd9Sstevel@tonic-gate 
1121d62bc4baSyz147064 	rsrc = get_link_resource(pif.pi_ifname);
1122d62bc4baSyz147064 	if (rsrc == NULL) {
1123d62bc4baSyz147064 		rcm_log_message(RCM_ERROR,
1124d62bc4baSyz147064 		    _("IP: get_link_resource(%s) failed\n"),
1125d62bc4baSyz147064 		    lifreq.lifr_name);
1126d62bc4baSyz147064 		return (-1);
1127d62bc4baSyz147064 	}
11287c478bd9Sstevel@tonic-gate 
1129d62bc4baSyz147064 	probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
11307c478bd9Sstevel@tonic-gate 	if (probe != NULL) {
1131d62bc4baSyz147064 		free(rsrc);
11327c478bd9Sstevel@tonic-gate 		probe->ip_cachestate &= ~(CACHE_IF_STALE);
11337c478bd9Sstevel@tonic-gate 	} else {
11347c478bd9Sstevel@tonic-gate 		if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) {
11357c478bd9Sstevel@tonic-gate 			/* malloc errors are bad */
1136d62bc4baSyz147064 			free(rsrc);
11377c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
11387c478bd9Sstevel@tonic-gate 			    strerror(errno));
11397c478bd9Sstevel@tonic-gate 			return (-1);
11407c478bd9Sstevel@tonic-gate 		}
11417c478bd9Sstevel@tonic-gate 
1142d62bc4baSyz147064 		probe->ip_resource = rsrc;
11437c478bd9Sstevel@tonic-gate 		probe->ip_pif = NULL;
11447c478bd9Sstevel@tonic-gate 		probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY;
11457c478bd9Sstevel@tonic-gate 		probe->ip_cachestate |= CACHE_IF_NEW;
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 		cache_insert(probe);
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	probepif = probe->ip_pif;
11517c478bd9Sstevel@tonic-gate 	if (probepif != NULL) {
11527c478bd9Sstevel@tonic-gate 		/* Check if lifs need to be updated */
11537c478bd9Sstevel@tonic-gate 		probelif = probepif->pi_lifs;
11547c478bd9Sstevel@tonic-gate 		while (probelif != NULL) {
11557c478bd9Sstevel@tonic-gate 			if ((probelif->li_ifnum == ifnumber) &&
11567c478bd9Sstevel@tonic-gate 			    (probelif->li_addr.family == ifaddr.ss_family)) {
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_TRACE2,
11597c478bd9Sstevel@tonic-gate 				    "IP: refreshing lifs for %s, ifnum=%d\n",
11607c478bd9Sstevel@tonic-gate 				    pif.pi_ifname, probelif->li_ifnum);
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate 				/* refresh lif properties */
11637c478bd9Sstevel@tonic-gate 				(void) memcpy(&probelif->li_addr, &ifaddr,
11647c478bd9Sstevel@tonic-gate 				    sizeof (probelif->li_addr));
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 				probelif->li_ifflags = ifflags;
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 				lif_listed++;
11697c478bd9Sstevel@tonic-gate 				probelif->li_cachestate &= ~(CACHE_IF_STALE);
11707c478bd9Sstevel@tonic-gate 				break;
11717c478bd9Sstevel@tonic-gate 			}
11727c478bd9Sstevel@tonic-gate 			probelif = probelif->li_next;
11737c478bd9Sstevel@tonic-gate 		}
11747c478bd9Sstevel@tonic-gate 	}
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	if (probepif == NULL) {
11777c478bd9Sstevel@tonic-gate 		if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) {
11787c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
11797c478bd9Sstevel@tonic-gate 			    strerror(errno));
11807c478bd9Sstevel@tonic-gate 			if (probe->ip_pif == NULL) {
11817c478bd9Sstevel@tonic-gate 				/* we created it, so clean it up */
11827c478bd9Sstevel@tonic-gate 				free(probe);
11837c478bd9Sstevel@tonic-gate 			}
11847c478bd9Sstevel@tonic-gate 			return (-1);
11857c478bd9Sstevel@tonic-gate 		}
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 		probe->ip_pif = probepif;
11887c478bd9Sstevel@tonic-gate 
11897c478bd9Sstevel@tonic-gate 		/* Save interface name */
11907c478bd9Sstevel@tonic-gate 		(void) memcpy(&probepif->pi_ifname, &pif.pi_ifname,
11917c478bd9Sstevel@tonic-gate 		    sizeof (pif.pi_ifname));
11927c478bd9Sstevel@tonic-gate 	}
11937c478bd9Sstevel@tonic-gate 
1194e11c3f44Smeem 	/* save the group name */
1195e11c3f44Smeem 	(void) strlcpy(probepif->pi_grname, pif.pi_grname,
1196e11c3f44Smeem 	    sizeof (pif.pi_grname));
11977c478bd9Sstevel@tonic-gate 
11987c478bd9Sstevel@tonic-gate 	/* add lif, if this is a lif and it is not in cache */
11997c478bd9Sstevel@tonic-gate 	if (!lif_listed) {
12007c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n",
12017c478bd9Sstevel@tonic-gate 		    pif.pi_ifname);
12027c478bd9Sstevel@tonic-gate 
12037c478bd9Sstevel@tonic-gate 		if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) {
12047c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
12057c478bd9Sstevel@tonic-gate 			    strerror(errno));
12067c478bd9Sstevel@tonic-gate 			return (-1);
12077c478bd9Sstevel@tonic-gate 		}
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 		/* save lif properties */
12107c478bd9Sstevel@tonic-gate 		(void) memcpy(&probelif->li_addr, &ifaddr,
12117c478bd9Sstevel@tonic-gate 		    sizeof (probelif->li_addr));
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 		probelif->li_ifnum = ifnumber;
12147c478bd9Sstevel@tonic-gate 		probelif->li_ifflags = ifflags;
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 		/* insert us at the head of the lif list */
12177c478bd9Sstevel@tonic-gate 		probelif->li_next = probepif->pi_lifs;
12187c478bd9Sstevel@tonic-gate 		if (probelif->li_next != NULL) {
12197c478bd9Sstevel@tonic-gate 			probelif->li_next->li_prev = probelif;
12207c478bd9Sstevel@tonic-gate 		}
12217c478bd9Sstevel@tonic-gate 		probelif->li_prev = NULL;
12227c478bd9Sstevel@tonic-gate 		probelif->li_pif = probepif;
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 		probepif->pi_lifs = probelif;
12257c478bd9Sstevel@tonic-gate 	}
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n",
12287c478bd9Sstevel@tonic-gate 	    probe->ip_resource);
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	return (0);
12317c478bd9Sstevel@tonic-gate }
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate /*
12347c478bd9Sstevel@tonic-gate  * update_ipifs() - Determine all network interfaces in the system
12357c478bd9Sstevel@tonic-gate  *		  Call with cache_lock held
12367c478bd9Sstevel@tonic-gate  */
12377c478bd9Sstevel@tonic-gate static int
12387c478bd9Sstevel@tonic-gate update_ipifs(rcm_handle_t *hd, int af)
12397c478bd9Sstevel@tonic-gate {
12407c478bd9Sstevel@tonic-gate 
12416e91bba0SGirish Moodalbail 	struct ifaddrs *ifa;
12426e91bba0SGirish Moodalbail 	ipadm_addr_info_t *ainfo;
12436e91bba0SGirish Moodalbail 	ipadm_addr_info_t *ptr;
12446e91bba0SGirish Moodalbail 	ipadm_status_t status;
12456e91bba0SGirish Moodalbail 	int sock;
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
12487c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
12497c478bd9Sstevel@tonic-gate 		    _("IP: failure opening %s socket: %s\n"),
12507c478bd9Sstevel@tonic-gate 		    af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
12517c478bd9Sstevel@tonic-gate 		return (-1);
12527c478bd9Sstevel@tonic-gate 	}
12537c478bd9Sstevel@tonic-gate 
12546e91bba0SGirish Moodalbail 	status = ipadm_addr_info(ip_handle, NULL, &ainfo, IPADM_OPT_ZEROADDR,
12556e91bba0SGirish Moodalbail 	    LIFC_UNDER_IPMP);
12566e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS) {
12577c478bd9Sstevel@tonic-gate 		(void) close(sock);
12587c478bd9Sstevel@tonic-gate 		return (-1);
12597c478bd9Sstevel@tonic-gate 	}
12606e91bba0SGirish Moodalbail 	for (ptr = ainfo; ptr; ptr = IA_NEXT(ptr)) {
12616e91bba0SGirish Moodalbail 		ifa = &ptr->ia_ifa;
12626e91bba0SGirish Moodalbail 		if (ptr->ia_state != IFA_DISABLED &&
1263*64639aafSDarren Reed 		    af == ifa->ifa_addr->sa_family)
12646e91bba0SGirish Moodalbail 			(void) update_pif(hd, af, sock, ifa);
12657c478bd9Sstevel@tonic-gate 	}
12667c478bd9Sstevel@tonic-gate 	(void) close(sock);
12676e91bba0SGirish Moodalbail 	ipadm_free_addr_info(ainfo);
12687c478bd9Sstevel@tonic-gate 	return (0);
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate /*
12727c478bd9Sstevel@tonic-gate  * update_cache() - Update cache with latest interface info
12737c478bd9Sstevel@tonic-gate  */
12747c478bd9Sstevel@tonic-gate static int
12757c478bd9Sstevel@tonic-gate update_cache(rcm_handle_t *hd)
12767c478bd9Sstevel@tonic-gate {
12777c478bd9Sstevel@tonic-gate 	ip_cache_t *probe;
12787c478bd9Sstevel@tonic-gate 	struct ip_lif *lif;
12797c478bd9Sstevel@tonic-gate 	struct ip_lif *nextlif;
12807c478bd9Sstevel@tonic-gate 	int rv;
12817c478bd9Sstevel@tonic-gate 	int i;
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: update_cache\n");
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	/* first we walk the entire cache, marking each entry stale */
12887c478bd9Sstevel@tonic-gate 	probe = cache_head.ip_next;
12897c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
12907c478bd9Sstevel@tonic-gate 		probe->ip_cachestate |= CACHE_IF_STALE;
12917c478bd9Sstevel@tonic-gate 		if ((probe->ip_pif != NULL) &&
12927c478bd9Sstevel@tonic-gate 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
12937c478bd9Sstevel@tonic-gate 			while (lif != NULL) {
12947c478bd9Sstevel@tonic-gate 				lif->li_cachestate |= CACHE_IF_STALE;
12957c478bd9Sstevel@tonic-gate 				lif = lif->li_next;
12967c478bd9Sstevel@tonic-gate 			}
12977c478bd9Sstevel@tonic-gate 		}
12987c478bd9Sstevel@tonic-gate 		probe = probe->ip_next;
12997c478bd9Sstevel@tonic-gate 	}
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n");
13027c478bd9Sstevel@tonic-gate 	if (update_ipifs(hd, AF_INET) < 0) {
13037c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
13047c478bd9Sstevel@tonic-gate 		return (-1);
13057c478bd9Sstevel@tonic-gate 	}
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n");
13087c478bd9Sstevel@tonic-gate 	if (update_ipifs(hd, AF_INET6) < 0) {
13097c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
13107c478bd9Sstevel@tonic-gate 		return (-1);
13117c478bd9Sstevel@tonic-gate 	}
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	probe = cache_head.ip_next;
13147c478bd9Sstevel@tonic-gate 	/* unregister devices that are not offlined and still in cache */
13157c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
13167c478bd9Sstevel@tonic-gate 		ip_cache_t *freeit;
13177c478bd9Sstevel@tonic-gate 		if ((probe->ip_pif != NULL) &&
13187c478bd9Sstevel@tonic-gate 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
13197c478bd9Sstevel@tonic-gate 			/* clear stale lifs */
13207c478bd9Sstevel@tonic-gate 			while (lif != NULL) {
13217c478bd9Sstevel@tonic-gate 				if (lif->li_cachestate & CACHE_IF_STALE) {
13227c478bd9Sstevel@tonic-gate 					nextlif = lif->li_next;
13237c478bd9Sstevel@tonic-gate 					if (lif->li_prev != NULL)
13247c478bd9Sstevel@tonic-gate 						lif->li_prev->li_next = nextlif;
13257c478bd9Sstevel@tonic-gate 					if (nextlif != NULL)
13267c478bd9Sstevel@tonic-gate 						nextlif->li_prev = lif->li_prev;
13277c478bd9Sstevel@tonic-gate 					if (probe->ip_pif->pi_lifs == lif)
13287c478bd9Sstevel@tonic-gate 						probe->ip_pif->pi_lifs =
13297c478bd9Sstevel@tonic-gate 						    nextlif;
13307c478bd9Sstevel@tonic-gate 					for (i = 0; i < IP_MAX_MODS; i++) {
13317c478bd9Sstevel@tonic-gate 						free(lif->li_modules[i]);
13327c478bd9Sstevel@tonic-gate 					}
13337c478bd9Sstevel@tonic-gate 					free(lif->li_reconfig);
13347c478bd9Sstevel@tonic-gate 					free(lif);
13357c478bd9Sstevel@tonic-gate 					lif = nextlif;
13367c478bd9Sstevel@tonic-gate 				} else {
13377c478bd9Sstevel@tonic-gate 					lif = lif->li_next;
13387c478bd9Sstevel@tonic-gate 				}
13397c478bd9Sstevel@tonic-gate 			}
13407c478bd9Sstevel@tonic-gate 		}
13417c478bd9Sstevel@tonic-gate 		if ((probe->ip_cachestate & CACHE_IF_STALE) &&
13427c478bd9Sstevel@tonic-gate 		    !(probe->ip_cachestate & CACHE_IF_OFFLINED)) {
13437c478bd9Sstevel@tonic-gate 			(void) rcm_unregister_interest(hd, probe->ip_resource,
13447c478bd9Sstevel@tonic-gate 			    0);
13457c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
13467c478bd9Sstevel@tonic-gate 			    probe->ip_resource);
13477c478bd9Sstevel@tonic-gate 			freeit = probe;
13487c478bd9Sstevel@tonic-gate 			probe = probe->ip_next;
13497c478bd9Sstevel@tonic-gate 			cache_remove(freeit);
13507c478bd9Sstevel@tonic-gate 			free_node(freeit);
13517c478bd9Sstevel@tonic-gate 			continue;
13527c478bd9Sstevel@tonic-gate 		}
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 		if (!(probe->ip_cachestate & CACHE_IF_NEW)) {
13557c478bd9Sstevel@tonic-gate 			probe = probe->ip_next;
13567c478bd9Sstevel@tonic-gate 			continue;
13577c478bd9Sstevel@tonic-gate 		}
13587c478bd9Sstevel@tonic-gate 
13597c478bd9Sstevel@tonic-gate 		rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL);
13607c478bd9Sstevel@tonic-gate 		if (rv != RCM_SUCCESS) {
13617c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
13627c478bd9Sstevel@tonic-gate 			    _("IP: failed to register %s\n"),
13637c478bd9Sstevel@tonic-gate 			    probe->ip_resource);
13647c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cache_lock);
13657c478bd9Sstevel@tonic-gate 			return (-1);
13667c478bd9Sstevel@tonic-gate 		} else {
13677c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
13687c478bd9Sstevel@tonic-gate 			    probe->ip_resource);
13697c478bd9Sstevel@tonic-gate 			probe->ip_cachestate &= ~(CACHE_IF_NEW);
13707c478bd9Sstevel@tonic-gate 		}
13717c478bd9Sstevel@tonic-gate 		probe = probe->ip_next;
13727c478bd9Sstevel@tonic-gate 	}
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
13757c478bd9Sstevel@tonic-gate 	return (0);
13767c478bd9Sstevel@tonic-gate }
13777c478bd9Sstevel@tonic-gate 
13787c478bd9Sstevel@tonic-gate /*
13797c478bd9Sstevel@tonic-gate  * free_cache() - Empty the cache
13807c478bd9Sstevel@tonic-gate  */
13817c478bd9Sstevel@tonic-gate static void
13827c478bd9Sstevel@tonic-gate free_cache()
13837c478bd9Sstevel@tonic-gate {
13847c478bd9Sstevel@tonic-gate 	ip_cache_t *probe;
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: free_cache\n");
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
13897c478bd9Sstevel@tonic-gate 	probe = cache_head.ip_next;
13907c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
13917c478bd9Sstevel@tonic-gate 		cache_remove(probe);
13927c478bd9Sstevel@tonic-gate 		free_node(probe);
13937c478bd9Sstevel@tonic-gate 		probe = cache_head.ip_next;
13947c478bd9Sstevel@tonic-gate 	}
13957c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
13967c478bd9Sstevel@tonic-gate }
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate /*
13997c478bd9Sstevel@tonic-gate  * ip_log_err() - RCM error log wrapper
14007c478bd9Sstevel@tonic-gate  */
14017c478bd9Sstevel@tonic-gate static void
14027c478bd9Sstevel@tonic-gate ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
14037c478bd9Sstevel@tonic-gate {
1404d62bc4baSyz147064 	char *ifname = NULL;
1405e11c3f44Smeem 	int size;
14067c478bd9Sstevel@tonic-gate 	const char *errfmt;
1407e11c3f44Smeem 	char *error = NULL;
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	if ((node != NULL) && (node->ip_pif != NULL) &&
14107c478bd9Sstevel@tonic-gate 	    (node->ip_pif->pi_ifname != NULL)) {
1411d62bc4baSyz147064 		ifname = node->ip_pif->pi_ifname;
14127c478bd9Sstevel@tonic-gate 	}
14137c478bd9Sstevel@tonic-gate 
1414d62bc4baSyz147064 	if (ifname == NULL) {
14157c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg);
14167c478bd9Sstevel@tonic-gate 		errfmt = _("IP: %s");
1417e11c3f44Smeem 		size = strlen(errfmt) + strlen(errmsg) + 1;
1418e11c3f44Smeem 		if (errorp != NULL && (error = malloc(size)) != NULL)
1419e11c3f44Smeem 			(void) snprintf(error, size, errfmt, errmsg);
14207c478bd9Sstevel@tonic-gate 	} else {
1421d62bc4baSyz147064 		rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname);
14227c478bd9Sstevel@tonic-gate 		errfmt = _("IP: %s(%s)");
1423e11c3f44Smeem 		size = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1;
1424e11c3f44Smeem 		if (errorp != NULL && (error = malloc(size)) != NULL)
1425e11c3f44Smeem 			(void) snprintf(error, size, errfmt, errmsg, ifname);
14267c478bd9Sstevel@tonic-gate 	}
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	if (errorp != NULL)
14297c478bd9Sstevel@tonic-gate 		*errorp = error;
14307c478bd9Sstevel@tonic-gate }
14317c478bd9Sstevel@tonic-gate 
14327c478bd9Sstevel@tonic-gate /*
14337c478bd9Sstevel@tonic-gate  * if_cfginfo() - Save off the config info for all interfaces
14347c478bd9Sstevel@tonic-gate  */
14357c478bd9Sstevel@tonic-gate static int
14367c478bd9Sstevel@tonic-gate if_cfginfo(ip_cache_t *node, uint_t force)
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
14397c478bd9Sstevel@tonic-gate 	ip_pif_t *pif;
14407c478bd9Sstevel@tonic-gate 	int i;
14417c478bd9Sstevel@tonic-gate 	FILE *fp;
14427c478bd9Sstevel@tonic-gate 	char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
14437c478bd9Sstevel@tonic-gate 	char buf[MAX_RECONFIG_SIZE];
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource);
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	pif = node->ip_pif;
14487c478bd9Sstevel@tonic-gate 	lif = pif->pi_lifs;
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	while (lif != NULL) {
14517c478bd9Sstevel@tonic-gate 		/* Make a list of modules pushed and save */
14527c478bd9Sstevel@tonic-gate 		if (lif->li_ifnum == 0) {	/* physical instance */
14537c478bd9Sstevel@tonic-gate 			if (get_modlist(pif->pi_ifname, lif) == -1) {
14547c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_ERROR,
14557c478bd9Sstevel@tonic-gate 				    _("IP: get modlist error (%s) %s\n"),
14567c478bd9Sstevel@tonic-gate 				    pif->pi_ifname, strerror(errno));
1457e11c3f44Smeem 				clr_cfg_state(pif);
14587c478bd9Sstevel@tonic-gate 				return (-1);
14597c478bd9Sstevel@tonic-gate 			}
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 			if (!force) {
14627c478bd9Sstevel@tonic-gate 				/* Look if unknown modules have been inserted */
14637c478bd9Sstevel@tonic-gate 				for (i = (lif->li_modcnt - 2); i > 0; i--) {
14647c478bd9Sstevel@tonic-gate 					if (modop(pif->pi_ifname,
14657c478bd9Sstevel@tonic-gate 					    lif->li_modules[i],
14667c478bd9Sstevel@tonic-gate 					    i, MOD_CHECK) == -1) {
14677c478bd9Sstevel@tonic-gate 						rcm_log_message(RCM_ERROR,
14687c478bd9Sstevel@tonic-gate 						    _("IP: module %s@%d\n"),
14697c478bd9Sstevel@tonic-gate 						    lif->li_modules[i], i);
1470e11c3f44Smeem 						clr_cfg_state(pif);
14717c478bd9Sstevel@tonic-gate 						return (-1);
14727c478bd9Sstevel@tonic-gate 					}
14737c478bd9Sstevel@tonic-gate 				}
14747c478bd9Sstevel@tonic-gate 			}
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 			/* Last module is the device driver, so ignore that */
14777c478bd9Sstevel@tonic-gate 			for (i = (lif->li_modcnt - 2); i > 0; i--) {
14787c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_TRACE2,
14797c478bd9Sstevel@tonic-gate 				    "IP: modremove Pos = %d, Module = %s \n",
14807c478bd9Sstevel@tonic-gate 				    i, lif->li_modules[i]);
14817c478bd9Sstevel@tonic-gate 				if (modop(pif->pi_ifname, lif->li_modules[i],
14827c478bd9Sstevel@tonic-gate 				    i, MOD_REMOVE) == -1) {
14837c478bd9Sstevel@tonic-gate 					while (i != (lif->li_modcnt - 2)) {
14847c478bd9Sstevel@tonic-gate 						if (modop(pif->pi_ifname,
14857c478bd9Sstevel@tonic-gate 						    lif->li_modules[i],
14867c478bd9Sstevel@tonic-gate 						    i, MOD_INSERT) == -1) {
14877c478bd9Sstevel@tonic-gate 							/* Gross error */
14887c478bd9Sstevel@tonic-gate 							rcm_log_message(
14897c478bd9Sstevel@tonic-gate 							    RCM_ERROR,
14907c478bd9Sstevel@tonic-gate 							    _("IP: if_cfginfo"
14917c478bd9Sstevel@tonic-gate 							    "(%s) %s\n"),
14927c478bd9Sstevel@tonic-gate 							    pif->pi_ifname,
14937c478bd9Sstevel@tonic-gate 							    strerror(errno));
14947c478bd9Sstevel@tonic-gate 							clr_cfg_state(pif);
14957c478bd9Sstevel@tonic-gate 							return (-1);
14967c478bd9Sstevel@tonic-gate 						}
14977c478bd9Sstevel@tonic-gate 						i++;
14987c478bd9Sstevel@tonic-gate 					}
14997c478bd9Sstevel@tonic-gate 					rcm_log_message(
15007c478bd9Sstevel@tonic-gate 					    RCM_ERROR,
15017c478bd9Sstevel@tonic-gate 					    _("IP: if_cfginfo(%s): modremove "
15027c478bd9Sstevel@tonic-gate 					    "%s failed: %s\n"), pif->pi_ifname,
15037c478bd9Sstevel@tonic-gate 					    lif->li_modules[i],
15047c478bd9Sstevel@tonic-gate 					    strerror(errno));
15057c478bd9Sstevel@tonic-gate 					clr_cfg_state(pif);
15067c478bd9Sstevel@tonic-gate 					return (-1);
15077c478bd9Sstevel@tonic-gate 				}
15087c478bd9Sstevel@tonic-gate 			}
15097c478bd9Sstevel@tonic-gate 		}
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate 		/* Save reconfiguration information */
15127c478bd9Sstevel@tonic-gate 		if (lif->li_ifflags & IFF_IPV4) {
15137c478bd9Sstevel@tonic-gate 			(void) snprintf(syscmd, sizeof (syscmd),
1514e11c3f44Smeem 			    "%s %s:%d configinfo\n", SBIN_IFCONFIG,
15157c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum);
15167c478bd9Sstevel@tonic-gate 		} else if (lif->li_ifflags & IFF_IPV6) {
15177c478bd9Sstevel@tonic-gate 			(void) snprintf(syscmd, sizeof (syscmd),
1518e11c3f44Smeem 			    "%s %s:%d inet6 configinfo\n", SBIN_IFCONFIG,
15197c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum);
15207c478bd9Sstevel@tonic-gate 		}
15217c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd);
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 		/* open a pipe to retrieve reconfiguration info */
15247c478bd9Sstevel@tonic-gate 		if ((fp = popen(syscmd, "r")) == NULL) {
15257c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
15267c478bd9Sstevel@tonic-gate 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
15277c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
1528e11c3f44Smeem 			clr_cfg_state(pif);
15297c478bd9Sstevel@tonic-gate 			return (-1);
15307c478bd9Sstevel@tonic-gate 		}
15317c478bd9Sstevel@tonic-gate 		bzero(buf, MAX_RECONFIG_SIZE);
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 		if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) {
15347c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
15357c478bd9Sstevel@tonic-gate 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
15367c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
15377c478bd9Sstevel@tonic-gate 			(void) pclose(fp);
1538e11c3f44Smeem 			clr_cfg_state(pif);
15397c478bd9Sstevel@tonic-gate 			return (-1);
15407c478bd9Sstevel@tonic-gate 		}
15417c478bd9Sstevel@tonic-gate 		(void) pclose(fp);
15427c478bd9Sstevel@tonic-gate 
1543e11c3f44Smeem 		if ((lif->li_reconfig = strdup(buf)) == NULL) {
15447c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
15457c478bd9Sstevel@tonic-gate 			    _("IP: malloc error (%s) %s\n"),
15467c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, strerror(errno));
1547e11c3f44Smeem 			clr_cfg_state(pif);
15487c478bd9Sstevel@tonic-gate 			return (-1);
15497c478bd9Sstevel@tonic-gate 		}
15507c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG,
15517c478bd9Sstevel@tonic-gate 		    "IP: if_cfginfo: reconfig string(%s:%d) = %s\n",
15527c478bd9Sstevel@tonic-gate 		    pif->pi_ifname, lif->li_ifnum, lif->li_reconfig);
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 		lif = lif->li_next;
15557c478bd9Sstevel@tonic-gate 	}
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 	return (0);
15587c478bd9Sstevel@tonic-gate }
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate /*
15617c478bd9Sstevel@tonic-gate  * if_unplumb() - Unplumb the interface
15627c478bd9Sstevel@tonic-gate  *		Save off the modlist, ifconfig options and unplumb.
15637c478bd9Sstevel@tonic-gate  *		Fail, if an unknown module lives between IP and driver and
15647c478bd9Sstevel@tonic-gate  *		force is not set
15657c478bd9Sstevel@tonic-gate  *		Call with cache_lock held
15667c478bd9Sstevel@tonic-gate  */
15677c478bd9Sstevel@tonic-gate static int
15687c478bd9Sstevel@tonic-gate if_unplumb(ip_cache_t *node)
15697c478bd9Sstevel@tonic-gate {
15707c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
1571e11c3f44Smeem 	ip_pif_t *pif = node->ip_pif;
1572e11c3f44Smeem 	boolean_t ipv4 = B_FALSE;
1573e11c3f44Smeem 	boolean_t ipv6 = B_FALSE;
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource);
15767c478bd9Sstevel@tonic-gate 
1577e11c3f44Smeem 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
15787c478bd9Sstevel@tonic-gate 		if (lif->li_ifflags & IFF_IPV4) {
1579e11c3f44Smeem 			ipv4 = B_TRUE;
15807c478bd9Sstevel@tonic-gate 		} else if (lif->li_ifflags & IFF_IPV6) {
1581e11c3f44Smeem 			ipv6 = B_TRUE;
15827c478bd9Sstevel@tonic-gate 		} else {
15837c478bd9Sstevel@tonic-gate 			/* Unlikely case */
15847c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
1585d62bc4baSyz147064 			    "IP: Unplumb ignored (%s:%d)\n",
15867c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum);
15877c478bd9Sstevel@tonic-gate 		}
15887c478bd9Sstevel@tonic-gate 	}
15897c478bd9Sstevel@tonic-gate 
1590e11c3f44Smeem 	if (ipv4 && !ifconfig(pif->pi_ifname, "inet", "unplumb", B_FALSE)) {
1591e11c3f44Smeem 		rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
15927c478bd9Sstevel@tonic-gate 		    pif->pi_ifname, strerror(errno));
15937c478bd9Sstevel@tonic-gate 		return (-1);
15947c478bd9Sstevel@tonic-gate 	}
1595e11c3f44Smeem 
1596e11c3f44Smeem 	if (ipv6 && !ifconfig(pif->pi_ifname, "inet6", "unplumb", B_FALSE)) {
1597e11c3f44Smeem 		rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
15987c478bd9Sstevel@tonic-gate 		    pif->pi_ifname, strerror(errno));
15997c478bd9Sstevel@tonic-gate 		return (-1);
16007c478bd9Sstevel@tonic-gate 	}
1601e11c3f44Smeem 
16027c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n",
16037c478bd9Sstevel@tonic-gate 	    node->ip_resource);
16047c478bd9Sstevel@tonic-gate 
16057c478bd9Sstevel@tonic-gate 	return (0);
16067c478bd9Sstevel@tonic-gate }
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate /*
16097c478bd9Sstevel@tonic-gate  * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface
16107c478bd9Sstevel@tonic-gate  *		instances and the logical interfaces in order, restoring
16117c478bd9Sstevel@tonic-gate  *		all ifconfig options
16127c478bd9Sstevel@tonic-gate  *		Call with cache_lock held
16137c478bd9Sstevel@tonic-gate  */
16147c478bd9Sstevel@tonic-gate static int
16157c478bd9Sstevel@tonic-gate if_replumb(ip_cache_t *node)
16167c478bd9Sstevel@tonic-gate {
16177c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
16187c478bd9Sstevel@tonic-gate 	ip_pif_t *pif;
16197c478bd9Sstevel@tonic-gate 	int i;
1620e11c3f44Smeem 	boolean_t success, ipmp;
1621e11c3f44Smeem 	const char *fstr;
1622e11c3f44Smeem 	char lifname[LIFNAMSIZ];
1623e11c3f44Smeem 	char buf[MAX_RECONFIG_SIZE];
1624e11c3f44Smeem 	int max_lifnum = 0;
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource);
16277c478bd9Sstevel@tonic-gate 
16287c478bd9Sstevel@tonic-gate 	/*
16297c478bd9Sstevel@tonic-gate 	 * Be extra careful about bringing up the interfaces in the
16307c478bd9Sstevel@tonic-gate 	 * correct order:
16317c478bd9Sstevel@tonic-gate 	 * - First plumb in the physical interface instances
16327c478bd9Sstevel@tonic-gate 	 * - modinsert the necessary modules@pos
16337c478bd9Sstevel@tonic-gate 	 * - Next, add the logical interfaces being careful about
16347c478bd9Sstevel@tonic-gate 	 *   the order, (follow the cached interface number li_ifnum order)
16357c478bd9Sstevel@tonic-gate 	 */
16367c478bd9Sstevel@tonic-gate 
16377c478bd9Sstevel@tonic-gate 	pif = node->ip_pif;
1638e11c3f44Smeem 	ipmp = (node->ip_pif->pi_grname[0] != '\0');
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate 	/*
16417c478bd9Sstevel@tonic-gate 	 * Make a first pass to plumb in physical interfaces and get a count
16427c478bd9Sstevel@tonic-gate 	 * of the max logical interfaces
16437c478bd9Sstevel@tonic-gate 	 */
1644e11c3f44Smeem 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1645e11c3f44Smeem 		max_lifnum = MAX(lif->li_ifnum, max_lifnum);
16467c478bd9Sstevel@tonic-gate 		if (lif->li_ifflags & IFF_IPV4) {
1647e11c3f44Smeem 			fstr = "inet";
16487c478bd9Sstevel@tonic-gate 		} else if (lif->li_ifflags & IFF_IPV6) {
1649e11c3f44Smeem 			fstr = "inet6";
16507c478bd9Sstevel@tonic-gate 		} else {
16517c478bd9Sstevel@tonic-gate 			/* Unlikely case */
16527c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
1653d62bc4baSyz147064 			    "IP: Re-plumb ignored (%s:%d)\n",
16547c478bd9Sstevel@tonic-gate 			    pif->pi_ifname, lif->li_ifnum);
16557c478bd9Sstevel@tonic-gate 			continue;
16567c478bd9Sstevel@tonic-gate 		}
16577c478bd9Sstevel@tonic-gate 
1658e11c3f44Smeem 		/* ignore logical interface instances */
1659e11c3f44Smeem 		if (lif->li_ifnum != 0)
1660e11c3f44Smeem 			continue;
1661e11c3f44Smeem 
1662e11c3f44Smeem 		if ((lif->li_ifflags & IFF_NOFAILOVER) || !ipmp) {
1663e11c3f44Smeem 			success = ifconfig("", "", lif->li_reconfig, B_FALSE);
1664e11c3f44Smeem 		} else {
1665e11c3f44Smeem 			(void) snprintf(buf, sizeof (buf), "plumb group %s",
1666e11c3f44Smeem 			    pif->pi_grname);
1667e11c3f44Smeem 			success = ifconfig(pif->pi_ifname, fstr, buf, B_FALSE);
16687c478bd9Sstevel@tonic-gate 		}
16697c478bd9Sstevel@tonic-gate 
1670e11c3f44Smeem 		if (!success) {
16717c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
1672e11c3f44Smeem 			    _("IP: Cannot plumb (%s) %s\n"), pif->pi_ifname,
1673e11c3f44Smeem 			    strerror(errno));
1674e11c3f44Smeem 			return (-1);
1675e11c3f44Smeem 		}
1676e11c3f44Smeem 
1677e11c3f44Smeem 		/*
1678e11c3f44Smeem 		 * Restart DHCP if necessary.
1679e11c3f44Smeem 		 */
1680e11c3f44Smeem 		if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1681e11c3f44Smeem 		    !ifconfig(pif->pi_ifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1682e11c3f44Smeem 			rcm_log_message(RCM_ERROR, _("IP: Cannot start DHCP "
1683e11c3f44Smeem 			    "(%s) %s\n"), pif->pi_ifname, strerror(errno));
16847c478bd9Sstevel@tonic-gate 			return (-1);
16857c478bd9Sstevel@tonic-gate 		}
16867c478bd9Sstevel@tonic-gate 
16877c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2,
16887c478bd9Sstevel@tonic-gate 		    "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt);
16897c478bd9Sstevel@tonic-gate 		/* modinsert modules in order, ignore driver(last) */
16907c478bd9Sstevel@tonic-gate 		for (i = 0; i < (lif->li_modcnt - 1); i++) {
16917c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_TRACE2,
16927c478bd9Sstevel@tonic-gate 			    "IP: modinsert: Pos = %d Mod = %s\n",
16937c478bd9Sstevel@tonic-gate 			    i, lif->li_modules[i]);
16947c478bd9Sstevel@tonic-gate 			if (modop(pif->pi_ifname, lif->li_modules[i], i,
16957c478bd9Sstevel@tonic-gate 			    MOD_INSERT) == -1) {
16967c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_ERROR,
16977c478bd9Sstevel@tonic-gate 				    _("IP: modinsert error(%s)\n"),
16987c478bd9Sstevel@tonic-gate 				    pif->pi_ifname);
16997c478bd9Sstevel@tonic-gate 				return (-1);
17007c478bd9Sstevel@tonic-gate 			}
17017c478bd9Sstevel@tonic-gate 		}
17027c478bd9Sstevel@tonic-gate 	}
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	/* Now, add all the logical interfaces in the correct order */
1705e11c3f44Smeem 	for (i = 1; i <= max_lifnum; i++) {
1706e11c3f44Smeem 		(void) snprintf(lifname, LIFNAMSIZ, "%s:%d", pif->pi_ifname, i);
1707e11c3f44Smeem 
17087c478bd9Sstevel@tonic-gate 		/* reset lif through every iteration */
1709e11c3f44Smeem 		for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1710e11c3f44Smeem 			/*
1711e11c3f44Smeem 			 * Process entries in order.  If the interface is
1712e11c3f44Smeem 			 * using IPMP, only process test addresses.
1713e11c3f44Smeem 			 */
1714e11c3f44Smeem 			if (lif->li_ifnum != i ||
1715e11c3f44Smeem 			    (ipmp && !(lif->li_ifflags & IFF_NOFAILOVER)))
1716e11c3f44Smeem 				continue;
1717e11c3f44Smeem 
1718e11c3f44Smeem 			if (!ifconfig("", "", lif->li_reconfig, B_FALSE)) {
17197c478bd9Sstevel@tonic-gate 				rcm_log_message(RCM_ERROR,
1720e11c3f44Smeem 				    _("IP: Cannot addif (%s) %s\n"), lifname,
1721e11c3f44Smeem 				    strerror(errno));
17227c478bd9Sstevel@tonic-gate 				return (-1);
17237c478bd9Sstevel@tonic-gate 			}
1724e11c3f44Smeem 
1725e11c3f44Smeem 			/*
1726e11c3f44Smeem 			 * Restart DHCP if necessary.
1727e11c3f44Smeem 			 */
1728e11c3f44Smeem 			if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1729e11c3f44Smeem 			    !ifconfig(lifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1730e11c3f44Smeem 				rcm_log_message(RCM_ERROR,
1731e11c3f44Smeem 				    _("IP: Cannot start DHCP (%s) %s\n"),
1732e11c3f44Smeem 				    lifname, strerror(errno));
1733e11c3f44Smeem 				return (-1);
17347c478bd9Sstevel@tonic-gate 			}
17357c478bd9Sstevel@tonic-gate 		}
17367c478bd9Sstevel@tonic-gate 	}
17377c478bd9Sstevel@tonic-gate 
17387c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n",
17397c478bd9Sstevel@tonic-gate 	    node->ip_resource);
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate 	return (0);
17427c478bd9Sstevel@tonic-gate }
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate /*
17457c478bd9Sstevel@tonic-gate  * clr_cfg_state() - Cleanup after errors in unplumb
17467c478bd9Sstevel@tonic-gate  */
17477c478bd9Sstevel@tonic-gate static void
17487c478bd9Sstevel@tonic-gate clr_cfg_state(ip_pif_t *pif)
17497c478bd9Sstevel@tonic-gate {
17507c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
17517c478bd9Sstevel@tonic-gate 	int i;
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	lif = pif->pi_lifs;
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	while (lif != NULL) {
17567c478bd9Sstevel@tonic-gate 		lif->li_modcnt = 0;
17577c478bd9Sstevel@tonic-gate 		free(lif->li_reconfig);
17587c478bd9Sstevel@tonic-gate 		lif->li_reconfig = NULL;
17597c478bd9Sstevel@tonic-gate 		for (i = 0; i < IP_MAX_MODS; i++) {
17607c478bd9Sstevel@tonic-gate 			free(lif->li_modules[i]);
17617c478bd9Sstevel@tonic-gate 			lif->li_modules[i] = NULL;
17627c478bd9Sstevel@tonic-gate 		}
17637c478bd9Sstevel@tonic-gate 		lif = lif->li_next;
17647c478bd9Sstevel@tonic-gate 	}
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate /*
1768e11c3f44Smeem  * Attempt to offline ip_cache_t `node'; returns an IPMP error code.
17697c478bd9Sstevel@tonic-gate  */
17707c478bd9Sstevel@tonic-gate static int
1771e11c3f44Smeem ip_ipmp_offline(ip_cache_t *node)
17727c478bd9Sstevel@tonic-gate {
1773e11c3f44Smeem 	int retval;
1774e11c3f44Smeem 	ipmp_handle_t handle;
17757c478bd9Sstevel@tonic-gate 
17767c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n");
17777c478bd9Sstevel@tonic-gate 
1778e11c3f44Smeem 	if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
17797c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
1780e11c3f44Smeem 		    _("IP: cannot create ipmp handle: %s\n"),
1781e11c3f44Smeem 		    ipmp_errmsg(retval));
1782e11c3f44Smeem 		return (retval);
17837c478bd9Sstevel@tonic-gate 	}
17847c478bd9Sstevel@tonic-gate 
1785e11c3f44Smeem 	retval = ipmp_offline(handle, node->ip_pif->pi_ifname, node->ip_ifred);
1786e11c3f44Smeem 	if (retval != IPMP_SUCCESS) {
1787e11c3f44Smeem 		rcm_log_message(RCM_ERROR, _("IP: ipmp_offline error: %s\n"),
1788e11c3f44Smeem 		    ipmp_errmsg(retval));
1789e11c3f44Smeem 	} else {
1790e11c3f44Smeem 		rcm_log_message(RCM_TRACE1, "IP: ipmp_offline success\n");
1791e11c3f44Smeem 	}
1792e11c3f44Smeem 
1793e11c3f44Smeem 	ipmp_close(handle);
1794e11c3f44Smeem 	return (retval);
17957c478bd9Sstevel@tonic-gate }
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate /*
1798e11c3f44Smeem  * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code.
17997c478bd9Sstevel@tonic-gate  */
18007c478bd9Sstevel@tonic-gate static int
18017c478bd9Sstevel@tonic-gate ip_ipmp_undo_offline(ip_cache_t *node)
18027c478bd9Sstevel@tonic-gate {
1803e11c3f44Smeem 	int retval;
1804e11c3f44Smeem 	ipmp_handle_t handle;
18057c478bd9Sstevel@tonic-gate 
1806e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_undo_offline\n");
18077c478bd9Sstevel@tonic-gate 
1808e11c3f44Smeem 	if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
18097c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
1810e11c3f44Smeem 		    _("IP: cannot create ipmp handle: %s\n"),
1811e11c3f44Smeem 		    ipmp_errmsg(retval));
1812e11c3f44Smeem 		return (retval);
18137c478bd9Sstevel@tonic-gate 	}
18147c478bd9Sstevel@tonic-gate 
1815e11c3f44Smeem 	retval = ipmp_undo_offline(handle, node->ip_pif->pi_ifname);
1816e11c3f44Smeem 	if (retval != IPMP_SUCCESS) {
1817e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
1818e11c3f44Smeem 		    _("IP: ipmp_undo_offline error: %s\n"),
1819e11c3f44Smeem 		    ipmp_errmsg(retval));
1820e11c3f44Smeem 	} else {
1821e11c3f44Smeem 		rcm_log_message(RCM_TRACE1, "IP: ipmp_undo_offline success\n");
1822e11c3f44Smeem 	}
1823e11c3f44Smeem 
1824e11c3f44Smeem 	ipmp_close(handle);
1825e11c3f44Smeem 	return (retval);
18267c478bd9Sstevel@tonic-gate }
18277c478bd9Sstevel@tonic-gate 
18287c478bd9Sstevel@tonic-gate /*
1829d62bc4baSyz147064  * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a
1830d62bc4baSyz147064  * dynamically allocated string containing the associated link resource
1831d62bc4baSyz147064  * name ("SUNW_datalink/<linkid>").
18327c478bd9Sstevel@tonic-gate  */
18337c478bd9Sstevel@tonic-gate static char *
1834d62bc4baSyz147064 get_link_resource(const char *link)
18357c478bd9Sstevel@tonic-gate {
1836d62bc4baSyz147064 	char		errmsg[DLADM_STRSIZE];
1837d62bc4baSyz147064 	datalink_id_t	linkid;
1838d62bc4baSyz147064 	uint32_t	flags;
1839d62bc4baSyz147064 	char		*resource;
1840d62bc4baSyz147064 	dladm_status_t	status;
18417c478bd9Sstevel@tonic-gate 
1842e11c3f44Smeem 	status = dladm_name2info(dld_handle, link, &linkid, &flags, NULL, NULL);
1843e11c3f44Smeem 	if (status != DLADM_STATUS_OK)
1844d62bc4baSyz147064 		goto fail;
18457c478bd9Sstevel@tonic-gate 
1846d62bc4baSyz147064 	if (!(flags & DLADM_OPT_ACTIVE)) {
1847d62bc4baSyz147064 		status = DLADM_STATUS_FAILED;
1848d62bc4baSyz147064 		goto fail;
1849d62bc4baSyz147064 	}
1850d62bc4baSyz147064 
1851d62bc4baSyz147064 	resource = malloc(RCM_LINK_RESOURCE_MAX);
1852d62bc4baSyz147064 	if (resource == NULL) {
1853595aa6e4Smeem 		rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"),
1854d62bc4baSyz147064 		    strerror(errno), link);
18557c478bd9Sstevel@tonic-gate 		return (NULL);
18567c478bd9Sstevel@tonic-gate 	}
18577c478bd9Sstevel@tonic-gate 
1858d62bc4baSyz147064 	(void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u",
1859d62bc4baSyz147064 	    RCM_LINK_PREFIX, linkid);
18607c478bd9Sstevel@tonic-gate 
1861d62bc4baSyz147064 	return (resource);
1862d62bc4baSyz147064 
1863d62bc4baSyz147064 fail:
1864d62bc4baSyz147064 	rcm_log_message(RCM_ERROR,
1865d62bc4baSyz147064 	    _("IP: get_link_resource for %s error(%s)\n"),
1866d62bc4baSyz147064 	    link, dladm_status2str(status, errmsg));
1867d62bc4baSyz147064 	return (NULL);
18687c478bd9Sstevel@tonic-gate }
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate /*
18717c478bd9Sstevel@tonic-gate  * modop() - Remove/insert a module
18727c478bd9Sstevel@tonic-gate  */
18737c478bd9Sstevel@tonic-gate static int
18747c478bd9Sstevel@tonic-gate modop(char *name, char *arg, int pos, char op)
18757c478bd9Sstevel@tonic-gate {
18767c478bd9Sstevel@tonic-gate 	char syscmd[LIFNAMSIZ+MAXPATHLEN];	/* must be big enough */
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name);
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate 	/* Nothing to do with "ip", "arp" */
18817c478bd9Sstevel@tonic-gate 	if ((arg == NULL) || (strcmp(arg, "") == 0) ||
18827c478bd9Sstevel@tonic-gate 	    STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) {
18837c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1, "IP: modop success\n");
18847c478bd9Sstevel@tonic-gate 		return (0);
18857c478bd9Sstevel@tonic-gate 	}
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	if (op == MOD_CHECK) {
18887c478bd9Sstevel@tonic-gate 		/*
18897c478bd9Sstevel@tonic-gate 		 * No known good modules (yet) apart from ip and arp
18907c478bd9Sstevel@tonic-gate 		 * which are handled above
18917c478bd9Sstevel@tonic-gate 		 */
18927c478bd9Sstevel@tonic-gate 		return (-1);
18937c478bd9Sstevel@tonic-gate 	}
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	if (op == MOD_REMOVE) {
18967c478bd9Sstevel@tonic-gate 		(void) snprintf(syscmd, sizeof (syscmd),
1897e11c3f44Smeem 		    "%s %s modremove %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
18987c478bd9Sstevel@tonic-gate 	} else if (op == MOD_INSERT) {
18997c478bd9Sstevel@tonic-gate 		(void) snprintf(syscmd, sizeof (syscmd),
1900e11c3f44Smeem 		    "%s %s modinsert %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
19017c478bd9Sstevel@tonic-gate 	} else {
19027c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
19037c478bd9Sstevel@tonic-gate 		    _("IP: modop(%s): unknown operation\n"), name);
19047c478bd9Sstevel@tonic-gate 		return (-1);
19057c478bd9Sstevel@tonic-gate 	}
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd);
19087c478bd9Sstevel@tonic-gate 	if (rcm_exec_cmd(syscmd) == -1) {
19097c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
19107c478bd9Sstevel@tonic-gate 		    _("IP: modop(%s): %s\n"), name, strerror(errno));
19117c478bd9Sstevel@tonic-gate 		return (-1);
19127c478bd9Sstevel@tonic-gate 	}
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: modop success\n");
19157c478bd9Sstevel@tonic-gate 	return (0);
19167c478bd9Sstevel@tonic-gate }
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate /*
19197c478bd9Sstevel@tonic-gate  * get_modlist() - return a list of pushed mid-stream modules
19207c478bd9Sstevel@tonic-gate  *		 Required memory is malloced to construct the list,
19217c478bd9Sstevel@tonic-gate  *		 Caller must free this memory list
19227c478bd9Sstevel@tonic-gate  *		 Call with cache_lock held
19237c478bd9Sstevel@tonic-gate  */
19247c478bd9Sstevel@tonic-gate static int
19257c478bd9Sstevel@tonic-gate get_modlist(char *name, ip_lif_t *lif)
19267c478bd9Sstevel@tonic-gate {
1927fc80c0dfSnordmark 	int mux_fd;
1928fc80c0dfSnordmark 	int muxid_fd;
19297c478bd9Sstevel@tonic-gate 	int fd;
19307c478bd9Sstevel@tonic-gate 	int i;
19317c478bd9Sstevel@tonic-gate 	int num_mods;
19327c478bd9Sstevel@tonic-gate 	struct lifreq lifr;
1933e11c3f44Smeem 	struct str_list strlist = { 0 };
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name);
19367c478bd9Sstevel@tonic-gate 
1937e11c3f44Smeem 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
19387c478bd9Sstevel@tonic-gate 	lifr.lifr_flags = lif->li_ifflags;
1939fc80c0dfSnordmark 	if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) {
19407c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name);
19417c478bd9Sstevel@tonic-gate 		return (-1);
19427c478bd9Sstevel@tonic-gate 	}
19437c478bd9Sstevel@tonic-gate 
19447c478bd9Sstevel@tonic-gate 	if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) {
19457c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
19467c478bd9Sstevel@tonic-gate 		    _("IP: get_modlist(%s): I_LIST(%s) \n"),
19477c478bd9Sstevel@tonic-gate 		    name, strerror(errno));
1948e11c3f44Smeem 		goto fail;
19497c478bd9Sstevel@tonic-gate 	}
19507c478bd9Sstevel@tonic-gate 
19517c478bd9Sstevel@tonic-gate 	strlist.sl_nmods = num_mods;
19527c478bd9Sstevel@tonic-gate 	strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods);
19537c478bd9Sstevel@tonic-gate 	if (strlist.sl_modlist == NULL) {
19547c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"),
19557c478bd9Sstevel@tonic-gate 		    name, strerror(errno));
1956e11c3f44Smeem 		goto fail;
19577c478bd9Sstevel@tonic-gate 	}
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 	if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
19607c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
19617c478bd9Sstevel@tonic-gate 		    _("IP: get_modlist(%s): I_LIST error: %s\n"),
19627c478bd9Sstevel@tonic-gate 		    name, strerror(errno));
1963e11c3f44Smeem 		goto fail;
19647c478bd9Sstevel@tonic-gate 	}
19657c478bd9Sstevel@tonic-gate 
19667c478bd9Sstevel@tonic-gate 	for (i = 0; i < strlist.sl_nmods; i++) {
1967e11c3f44Smeem 		lif->li_modules[i] = strdup(strlist.sl_modlist[i].l_name);
19687c478bd9Sstevel@tonic-gate 		if (lif->li_modules[i] == NULL) {
19697c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
19707c478bd9Sstevel@tonic-gate 			    _("IP: get_modlist(%s): %s\n"),
19717c478bd9Sstevel@tonic-gate 			    name, strerror(errno));
1972e11c3f44Smeem 			while (i > 0)
1973e11c3f44Smeem 				free(lif->li_modules[--i]);
1974e11c3f44Smeem 			goto fail;
19757c478bd9Sstevel@tonic-gate 		}
19767c478bd9Sstevel@tonic-gate 	}
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	lif->li_modcnt = strlist.sl_nmods;
19797c478bd9Sstevel@tonic-gate 	free(strlist.sl_modlist);
19807c478bd9Sstevel@tonic-gate 
19817c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name);
1982fc80c0dfSnordmark 	return (ip_plink(mux_fd, muxid_fd, fd, &lifr));
1983e11c3f44Smeem fail:
1984e11c3f44Smeem 	free(strlist.sl_modlist);
1985e11c3f44Smeem 	(void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
1986e11c3f44Smeem 	return (-1);
19877c478bd9Sstevel@tonic-gate }
19887c478bd9Sstevel@tonic-gate 
19897c478bd9Sstevel@tonic-gate /*
19907c478bd9Sstevel@tonic-gate  * ip_domux2fd() - Helper function for mod*() functions
19917c478bd9Sstevel@tonic-gate  *		 Stolen from ifconfig.c
19927c478bd9Sstevel@tonic-gate  */
19937c478bd9Sstevel@tonic-gate static int
1994fc80c0dfSnordmark ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr)
19957c478bd9Sstevel@tonic-gate {
1996fc80c0dfSnordmark 	int muxid_fd;
19977c478bd9Sstevel@tonic-gate 	char	*udp_dev_name;
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 	if (lifr->lifr_flags & IFF_IPV6) {
20007c478bd9Sstevel@tonic-gate 		udp_dev_name  = UDP6_DEV_NAME;
20017c478bd9Sstevel@tonic-gate 	} else {
20027c478bd9Sstevel@tonic-gate 		udp_dev_name  = UDP_DEV_NAME;
20037c478bd9Sstevel@tonic-gate 	}
20047c478bd9Sstevel@tonic-gate 
2005fc80c0dfSnordmark 	if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) {
20067c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
20077c478bd9Sstevel@tonic-gate 		    udp_dev_name, strerror(errno));
20087c478bd9Sstevel@tonic-gate 		return (-1);
20097c478bd9Sstevel@tonic-gate 	}
2010fc80c0dfSnordmark 	if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) {
2011fc80c0dfSnordmark 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2012fc80c0dfSnordmark 		    udp_dev_name, strerror(errno));
2013fc80c0dfSnordmark 		(void) close(muxid_fd);
2014fc80c0dfSnordmark 		return (-1);
2015fc80c0dfSnordmark 	}
2016fc80c0dfSnordmark 	if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) {
20177c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
20187c478bd9Sstevel@tonic-gate 		    _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"),
2019fc80c0dfSnordmark 		    udp_dev_name, strerror(errno));
2020fc80c0dfSnordmark 		(void) close(*mux_fd);
2021fc80c0dfSnordmark 		(void) close(muxid_fd);
20227c478bd9Sstevel@tonic-gate 		return (-1);
20237c478bd9Sstevel@tonic-gate 	}
20247c478bd9Sstevel@tonic-gate 
20257c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2,
20267c478bd9Sstevel@tonic-gate 	    "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n",
20277c478bd9Sstevel@tonic-gate 	    lifr->lifr_arp_muxid, lifr->lifr_ip_muxid);
20287c478bd9Sstevel@tonic-gate 
2029fc80c0dfSnordmark 	if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) {
20307c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
20317c478bd9Sstevel@tonic-gate 		    _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"),
20327c478bd9Sstevel@tonic-gate 		    udp_dev_name, strerror(errno));
2033fc80c0dfSnordmark 		(void) close(*mux_fd);
2034fc80c0dfSnordmark 		(void) close(muxid_fd);
20357c478bd9Sstevel@tonic-gate 		return (-1);
20367c478bd9Sstevel@tonic-gate 	}
2037fc80c0dfSnordmark 	if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) {
20387c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
20397c478bd9Sstevel@tonic-gate 		    _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"),
20407c478bd9Sstevel@tonic-gate 		    udp_dev_name, strerror(errno));
2041fc80c0dfSnordmark 		(void) close(*mux_fd);
2042fc80c0dfSnordmark 		(void) close(muxid_fd);
20437c478bd9Sstevel@tonic-gate 		return (-1);
20447c478bd9Sstevel@tonic-gate 	}
20457c478bd9Sstevel@tonic-gate 
2046fc80c0dfSnordmark 	/* Note: mux_fd and muxid_fd are closed in ip_plink below */
2047fc80c0dfSnordmark 	*muxid_fdp = muxid_fd;
20487c478bd9Sstevel@tonic-gate 	return (0);
20497c478bd9Sstevel@tonic-gate }
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate /*
20527c478bd9Sstevel@tonic-gate  * ip_plink() - Helper function for mod*() functions.
20537c478bd9Sstevel@tonic-gate  *	      Stolen from ifconfig.c
20547c478bd9Sstevel@tonic-gate  */
20557c478bd9Sstevel@tonic-gate static int
2056fc80c0dfSnordmark ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr)
20577c478bd9Sstevel@tonic-gate {
20587c478bd9Sstevel@tonic-gate 	int mux_id;
20597c478bd9Sstevel@tonic-gate 
2060fc80c0dfSnordmark 	if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) {
20617c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"),
20627c478bd9Sstevel@tonic-gate 		    UDP_DEV_NAME, strerror(errno));
2063fc80c0dfSnordmark 		(void) close(mux_fd);
2064fc80c0dfSnordmark 		(void) close(muxid_fd);
20657c478bd9Sstevel@tonic-gate 		(void) close(fd);
20667c478bd9Sstevel@tonic-gate 		return (-1);
20677c478bd9Sstevel@tonic-gate 	}
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	lifr->lifr_ip_muxid = mux_id;
2070fc80c0dfSnordmark 	if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) {
20717c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
20727c478bd9Sstevel@tonic-gate 		    _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"),
20737c478bd9Sstevel@tonic-gate 		    UDP_DEV_NAME, strerror(errno));
2074fc80c0dfSnordmark 		(void) close(mux_fd);
2075fc80c0dfSnordmark 		(void) close(muxid_fd);
20767c478bd9Sstevel@tonic-gate 		(void) close(fd);
20777c478bd9Sstevel@tonic-gate 		return (-1);
20787c478bd9Sstevel@tonic-gate 	}
20797c478bd9Sstevel@tonic-gate 
2080fc80c0dfSnordmark 	(void) close(mux_fd);
2081fc80c0dfSnordmark 	(void) close(muxid_fd);
20827c478bd9Sstevel@tonic-gate 	(void) close(fd);
20837c478bd9Sstevel@tonic-gate 	return (0);
20847c478bd9Sstevel@tonic-gate }
20857c478bd9Sstevel@tonic-gate 
20867c478bd9Sstevel@tonic-gate /*
20877c478bd9Sstevel@tonic-gate  * ip_onlinelist()
20887c478bd9Sstevel@tonic-gate  *
20897c478bd9Sstevel@tonic-gate  *	Notify online to IP address consumers.
20907c478bd9Sstevel@tonic-gate  */
2091e11c3f44Smeem /*ARGSUSED*/
20927c478bd9Sstevel@tonic-gate static int
20937c478bd9Sstevel@tonic-gate ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
20947c478bd9Sstevel@tonic-gate 		rcm_info_t **depend_info)
20957c478bd9Sstevel@tonic-gate {
20967c478bd9Sstevel@tonic-gate 	char **addrlist;
20977c478bd9Sstevel@tonic-gate 	int ret = RCM_SUCCESS;
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n");
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate 	addrlist = ip_get_addrlist(node);
21027c478bd9Sstevel@tonic-gate 	if (addrlist == NULL || addrlist[0] == NULL) {
21037c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n");
21047c478bd9Sstevel@tonic-gate 		ip_free_addrlist(addrlist);
21057c478bd9Sstevel@tonic-gate 		return (ret);
21067c478bd9Sstevel@tonic-gate 	}
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 	ret = rcm_notify_online_list(hd, addrlist, 0, depend_info);
21097c478bd9Sstevel@tonic-gate 
21107c478bd9Sstevel@tonic-gate 	ip_free_addrlist(addrlist);
21117c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n");
21127c478bd9Sstevel@tonic-gate 	return (ret);
21137c478bd9Sstevel@tonic-gate }
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate /*
21167c478bd9Sstevel@tonic-gate  * ip_offlinelist()
21177c478bd9Sstevel@tonic-gate  *
21187c478bd9Sstevel@tonic-gate  *	Offline IP address consumers.
21197c478bd9Sstevel@tonic-gate  */
2120e11c3f44Smeem /*ARGSUSED*/
21217c478bd9Sstevel@tonic-gate static int
21227c478bd9Sstevel@tonic-gate ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
21237c478bd9Sstevel@tonic-gate 	rcm_info_t **depend_info)
21247c478bd9Sstevel@tonic-gate {
21257c478bd9Sstevel@tonic-gate 	char **addrlist;
21267c478bd9Sstevel@tonic-gate 	int ret = RCM_SUCCESS;
21277c478bd9Sstevel@tonic-gate 
21287c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n");
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	addrlist = ip_get_addrlist(node);
21317c478bd9Sstevel@tonic-gate 	if (addrlist == NULL || addrlist[0] == NULL) {
21327c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n");
21337c478bd9Sstevel@tonic-gate 		ip_free_addrlist(addrlist);
21347c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
21357c478bd9Sstevel@tonic-gate 	}
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 	if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info))
21387c478bd9Sstevel@tonic-gate 	    != RCM_SUCCESS) {
21397c478bd9Sstevel@tonic-gate 		if (ret == RCM_FAILURE)
21407c478bd9Sstevel@tonic-gate 			(void) rcm_notify_online_list(hd, addrlist, 0, NULL);
21417c478bd9Sstevel@tonic-gate 
21427c478bd9Sstevel@tonic-gate 		ret = RCM_FAILURE;
21437c478bd9Sstevel@tonic-gate 	}
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate 	ip_free_addrlist(addrlist);
21467c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n");
21477c478bd9Sstevel@tonic-gate 	return (ret);
21487c478bd9Sstevel@tonic-gate }
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate /*
2151e11c3f44Smeem  * ip_get_addrlist() -	Get the list of IP addresses on this interface (node);
2152e11c3f44Smeem  *			This routine malloc()s required memory for the list.
2153e11c3f44Smeem  *			Returns the list on success, NULL on failure.
21547c478bd9Sstevel@tonic-gate  *			Call with cache_lock held.
21557c478bd9Sstevel@tonic-gate  */
21567c478bd9Sstevel@tonic-gate static char **
21577c478bd9Sstevel@tonic-gate ip_get_addrlist(ip_cache_t *node)
21587c478bd9Sstevel@tonic-gate {
21597c478bd9Sstevel@tonic-gate 	ip_lif_t *lif;
21607c478bd9Sstevel@tonic-gate 	char **addrlist = NULL;
2161e11c3f44Smeem 	int i, numifs;
2162e11c3f44Smeem 	size_t addrlistsize;
21637c478bd9Sstevel@tonic-gate 	char addrstr[INET6_ADDRSTRLEN];
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n",
21667c478bd9Sstevel@tonic-gate 	    node->ip_resource);
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	numifs = 0;
21697c478bd9Sstevel@tonic-gate 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
21707c478bd9Sstevel@tonic-gate 		numifs++;
21717c478bd9Sstevel@tonic-gate 	}
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	/*
21747c478bd9Sstevel@tonic-gate 	 * Allocate space for resource names list; add 1 and use calloc()
21757c478bd9Sstevel@tonic-gate 	 * so that the list is NULL-terminated.
21767c478bd9Sstevel@tonic-gate 	 */
21777c478bd9Sstevel@tonic-gate 	if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) {
21787c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
21797c478bd9Sstevel@tonic-gate 		    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
21807c478bd9Sstevel@tonic-gate 		    node->ip_resource, strerror(errno));
21817c478bd9Sstevel@tonic-gate 		return (NULL);
21827c478bd9Sstevel@tonic-gate 	}
21837c478bd9Sstevel@tonic-gate 
21847c478bd9Sstevel@tonic-gate 	for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL;
21857c478bd9Sstevel@tonic-gate 	    lif = lif->li_next, i++) {
21867c478bd9Sstevel@tonic-gate 
2187e11c3f44Smeem 		if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) {
21887c478bd9Sstevel@tonic-gate 			ip_free_addrlist(addrlist);
21897c478bd9Sstevel@tonic-gate 			return (NULL);
21907c478bd9Sstevel@tonic-gate 		}
21917c478bd9Sstevel@tonic-gate 
2192e11c3f44Smeem 		addrlistsize = strlen(addrstr) + sizeof (RCM_STR_SUNW_IP);
2193e11c3f44Smeem 		if ((addrlist[i] = malloc(addrlistsize)) == NULL) {
21947c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
21957c478bd9Sstevel@tonic-gate 			    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
21967c478bd9Sstevel@tonic-gate 			    node->ip_resource, strerror(errno));
21977c478bd9Sstevel@tonic-gate 			ip_free_addrlist(addrlist);
21987c478bd9Sstevel@tonic-gate 			return (NULL);
21997c478bd9Sstevel@tonic-gate 		}
2200e11c3f44Smeem 		(void) snprintf(addrlist[i], addrlistsize, "%s%s",
2201e11c3f44Smeem 		    RCM_STR_SUNW_IP, addrstr);
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]);
22047c478bd9Sstevel@tonic-gate 	}
22057c478bd9Sstevel@tonic-gate 
22067c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n",
22077c478bd9Sstevel@tonic-gate 	    node->ip_resource);
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	return (addrlist);
22107c478bd9Sstevel@tonic-gate }
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate static void
22137c478bd9Sstevel@tonic-gate ip_free_addrlist(char **addrlist)
22147c478bd9Sstevel@tonic-gate {
22157c478bd9Sstevel@tonic-gate 	int i;
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 	if (addrlist == NULL)
22187c478bd9Sstevel@tonic-gate 		return;
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 	for (i = 0; addrlist[i] != NULL; i++)
22217c478bd9Sstevel@tonic-gate 		free(addrlist[i]);
22227c478bd9Sstevel@tonic-gate 	free(addrlist);
22237c478bd9Sstevel@tonic-gate }
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate /*
22267c478bd9Sstevel@tonic-gate  * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
22277c478bd9Sstevel@tonic-gate  */
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate static void
2230d62bc4baSyz147064 ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
2231d62bc4baSyz147064     uint_t flags, rcm_info_t **depend_info)
22327c478bd9Sstevel@tonic-gate {
2233d62bc4baSyz147064 	char cached_name[RCM_LINK_RESOURCE_MAX];
22347c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
22357c478bd9Sstevel@tonic-gate 
2236d62bc4baSyz147064 	assert(linkid != DATALINK_INVALID_LINKID);
22377c478bd9Sstevel@tonic-gate 
2238d62bc4baSyz147064 	rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid);
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 	/* Check for the interface in the cache */
2241d62bc4baSyz147064 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2242d62bc4baSyz147064 	    RCM_LINK_PREFIX, linkid);
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
22457c478bd9Sstevel@tonic-gate 	if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) {
2246d62bc4baSyz147064 		rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"),
2247d62bc4baSyz147064 		    linkid);
22487c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
22497c478bd9Sstevel@tonic-gate 		return;
22507c478bd9Sstevel@tonic-gate 	}
22517c478bd9Sstevel@tonic-gate 	/*
2252e11c3f44Smeem 	 * Inform anonymous consumers about IP addresses being onlined.
22537c478bd9Sstevel@tonic-gate 	 */
22547c478bd9Sstevel@tonic-gate 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
22577c478bd9Sstevel@tonic-gate 
22587c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n");
22597c478bd9Sstevel@tonic-gate }
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate /*
22626e91bba0SGirish Moodalbail  * Gets the interface name for the given linkid. Returns -1 if there is
22636e91bba0SGirish Moodalbail  * any error. It fills in the interface name in `ifinst' if the interface
22646e91bba0SGirish Moodalbail  * is not already configured. Otherwise, it puts a null string in `ifinst'.
22657c478bd9Sstevel@tonic-gate  */
22667c478bd9Sstevel@tonic-gate static int
22676e91bba0SGirish Moodalbail if_configure_get_linkid(datalink_id_t linkid, char *ifinst, size_t len)
22687c478bd9Sstevel@tonic-gate {
2269d62bc4baSyz147064 	char cached_name[RCM_LINK_RESOURCE_MAX];
22707c478bd9Sstevel@tonic-gate 	ip_cache_t *node;
22717c478bd9Sstevel@tonic-gate 
22727c478bd9Sstevel@tonic-gate 	/* Check for the interface in the cache */
2273d62bc4baSyz147064 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2274d62bc4baSyz147064 	    RCM_LINK_PREFIX, linkid);
22757c478bd9Sstevel@tonic-gate 
2276e11c3f44Smeem 	/* Check if the interface is new or was not previously offlined */
22777c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
22787c478bd9Sstevel@tonic-gate 	if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) &&
22797c478bd9Sstevel@tonic-gate 	    (!(node->ip_cachestate & CACHE_IF_OFFLINED))) {
22807c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1,
2281d62bc4baSyz147064 		    _("IP: Skipping configured interface(%u)\n"), linkid);
22827c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
22836e91bba0SGirish Moodalbail 		*ifinst = '\0';
22847c478bd9Sstevel@tonic-gate 		return (0);
22857c478bd9Sstevel@tonic-gate 	}
22867c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
22877c478bd9Sstevel@tonic-gate 
22884ac67f02SAnurag S. Maskey 	if (dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, NULL, ifinst,
22896e91bba0SGirish Moodalbail 	    len) != DLADM_STATUS_OK) {
2290d62bc4baSyz147064 		rcm_log_message(RCM_ERROR,
2291d62bc4baSyz147064 		    _("IP: get %u link name failed\n"), linkid);
2292d62bc4baSyz147064 		return (-1);
2293d62bc4baSyz147064 	}
22946e91bba0SGirish Moodalbail 	return (0);
22956e91bba0SGirish Moodalbail }
22966e91bba0SGirish Moodalbail 
22976e91bba0SGirish Moodalbail /*
22986e91bba0SGirish Moodalbail  * if_configure_hostname() - Configure a physical interface after attach
22996e91bba0SGirish Moodalbail  * based on the information in /etc/hostname.*
23006e91bba0SGirish Moodalbail  */
23016e91bba0SGirish Moodalbail static int
23026e91bba0SGirish Moodalbail if_configure_hostname(datalink_id_t linkid)
23036e91bba0SGirish Moodalbail {
23046e91bba0SGirish Moodalbail 	FILE *hostfp, *host6fp;
23056e91bba0SGirish Moodalbail 	boolean_t ipmp = B_FALSE;
23066e91bba0SGirish Moodalbail 	char ifinst[MAXLINKNAMELEN];
23076e91bba0SGirish Moodalbail 	char cfgfile[MAXPATHLEN];
23086e91bba0SGirish Moodalbail 
23096e91bba0SGirish Moodalbail 	assert(linkid != DATALINK_INVALID_LINKID);
23106e91bba0SGirish Moodalbail 	rcm_log_message(RCM_TRACE1, _("IP: if_configure_hostname(%u)\n"),
23116e91bba0SGirish Moodalbail 	    linkid);
23126e91bba0SGirish Moodalbail 
23136e91bba0SGirish Moodalbail 	if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
23146e91bba0SGirish Moodalbail 		return (-1);
23156e91bba0SGirish Moodalbail 
23166e91bba0SGirish Moodalbail 	/* Check if the interface is already configured. */
23176e91bba0SGirish Moodalbail 	if (ifinst[0] == '\0')
23186e91bba0SGirish Moodalbail 		return (0);
2319d62bc4baSyz147064 
2320e11c3f44Smeem 	/*
2321e11c3f44Smeem 	 * Scan the IPv4 and IPv6 hostname files to see if (a) they exist
2322e11c3f44Smeem 	 * and (b) if either one places the interface into an IPMP group.
2323e11c3f44Smeem 	 */
2324e11c3f44Smeem 	(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifinst);
23257c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2326e11c3f44Smeem 	if ((hostfp = fopen(cfgfile, "r")) != NULL) {
2327e11c3f44Smeem 		if (isgrouped(cfgfile))
2328e11c3f44Smeem 			ipmp = B_TRUE;
23297c478bd9Sstevel@tonic-gate 	}
23307c478bd9Sstevel@tonic-gate 
2331e11c3f44Smeem 	(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifinst);
23327c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2333e11c3f44Smeem 	if ((host6fp = fopen(cfgfile, "r")) != NULL) {
2334e11c3f44Smeem 		if (!ipmp && isgrouped(cfgfile))
2335e11c3f44Smeem 			ipmp = B_TRUE;
23367c478bd9Sstevel@tonic-gate 	}
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 	/*
2339e11c3f44Smeem 	 * Configure the interface according to its hostname files.
23407c478bd9Sstevel@tonic-gate 	 */
2341e11c3f44Smeem 	if (hostfp != NULL &&
2342e11c3f44Smeem 	    if_config_inst(ifinst, hostfp, AF_INET, ipmp) == -1) {
2343e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
2344e11c3f44Smeem 		    _("IP: IPv4 Post-attach failed (%s)\n"), ifinst);
2345e11c3f44Smeem 		goto fail;
2346e11c3f44Smeem 	}
2347e11c3f44Smeem 
2348e11c3f44Smeem 	if (host6fp != NULL &&
2349e11c3f44Smeem 	    if_config_inst(ifinst, host6fp, AF_INET6, ipmp) == -1) {
2350e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
2351e11c3f44Smeem 		    _("IP: IPv6 Post-attach failed (%s)\n"), ifinst);
2352e11c3f44Smeem 		goto fail;
2353e11c3f44Smeem 	}
2354e11c3f44Smeem 
2355e11c3f44Smeem 	(void) fclose(hostfp);
2356e11c3f44Smeem 	(void) fclose(host6fp);
23576e91bba0SGirish Moodalbail 	rcm_log_message(RCM_TRACE1, "IP: if_configure_hostname(%s) success\n",
23586e91bba0SGirish Moodalbail 	    ifinst);
2359e11c3f44Smeem 	return (0);
2360e11c3f44Smeem fail:
2361e11c3f44Smeem 	(void) fclose(hostfp);
2362e11c3f44Smeem 	(void) fclose(host6fp);
2363e11c3f44Smeem 	return (-1);
2364e11c3f44Smeem }
2365e11c3f44Smeem 
2366e11c3f44Smeem /*
23676e91bba0SGirish Moodalbail  * if_configure_ipadm() - Configure a physical interface after attach
23686e91bba0SGirish Moodalbail  * Queries libipadm for persistent configuration information and then
23696e91bba0SGirish Moodalbail  * resurrects that persistent configuration.
23706e91bba0SGirish Moodalbail  */
23716e91bba0SGirish Moodalbail static int
23726e91bba0SGirish Moodalbail if_configure_ipadm(datalink_id_t linkid)
23736e91bba0SGirish Moodalbail {
23746e91bba0SGirish Moodalbail 	char ifinst[MAXLINKNAMELEN];
23756e91bba0SGirish Moodalbail 	boolean_t found;
23766e91bba0SGirish Moodalbail 	ipadm_if_info_t *ifinfo, *ptr;
23776e91bba0SGirish Moodalbail 	ipadm_status_t status;
23786e91bba0SGirish Moodalbail 
23796e91bba0SGirish Moodalbail 	assert(linkid != DATALINK_INVALID_LINKID);
23806e91bba0SGirish Moodalbail 	rcm_log_message(RCM_TRACE1, _("IP: if_configure_ipadm(%u)\n"),
23816e91bba0SGirish Moodalbail 	    linkid);
23826e91bba0SGirish Moodalbail 
23836e91bba0SGirish Moodalbail 	if (if_configure_get_linkid(linkid, ifinst, sizeof (ifinst)) != 0)
23846e91bba0SGirish Moodalbail 		return (-1);
23856e91bba0SGirish Moodalbail 
23866e91bba0SGirish Moodalbail 	/* Check if the interface is already configured. */
23876e91bba0SGirish Moodalbail 	if (ifinst[0] == '\0')
23886e91bba0SGirish Moodalbail 		return (0);
23896e91bba0SGirish Moodalbail 
23906e91bba0SGirish Moodalbail 	status = ipadm_if_info(ip_handle, ifinst, &ifinfo, 0, LIFC_UNDER_IPMP);
23916e91bba0SGirish Moodalbail 	if (status == IPADM_ENXIO)
23926e91bba0SGirish Moodalbail 		goto done;
23936e91bba0SGirish Moodalbail 	if (status != IPADM_SUCCESS) {
23946e91bba0SGirish Moodalbail 		rcm_log_message(RCM_ERROR,
23956e91bba0SGirish Moodalbail 		    _("IP: IPv4 Post-attach failed (%s) Error %s\n"),
23966e91bba0SGirish Moodalbail 		    ifinst, ipadm_status2str(status));
23976e91bba0SGirish Moodalbail 		goto fail;
23986e91bba0SGirish Moodalbail 	}
23996e91bba0SGirish Moodalbail 	if (ifinfo != NULL) {
24006e91bba0SGirish Moodalbail 		found = B_FALSE;
24016e91bba0SGirish Moodalbail 		for (ptr = ifinfo; ptr; ptr = ptr->ifi_next) {
24026e91bba0SGirish Moodalbail 			if (strncmp(ptr->ifi_name, ifinst,
24036e91bba0SGirish Moodalbail 			    sizeof (ifinst)) == 0) {
24046e91bba0SGirish Moodalbail 				found = B_TRUE;
24056e91bba0SGirish Moodalbail 				break;
24066e91bba0SGirish Moodalbail 			}
24076e91bba0SGirish Moodalbail 		}
24086e91bba0SGirish Moodalbail 		free(ifinfo);
24096e91bba0SGirish Moodalbail 		if (!found) {
24106e91bba0SGirish Moodalbail 			return (0);
24116e91bba0SGirish Moodalbail 		}
24126e91bba0SGirish Moodalbail 		if (if_hostname_exists(ifinst, AF_INET) ||
24136e91bba0SGirish Moodalbail 		    if_hostname_exists(ifinst, AF_INET6)) {
24146e91bba0SGirish Moodalbail 			rcm_log_message(RCM_WARNING,
24156e91bba0SGirish Moodalbail 			    _("IP: IPv4 Post-attach (%s) found both "
24166e91bba0SGirish Moodalbail 			    "/etc/hostname and ipadm persistent configuration. "
24176e91bba0SGirish Moodalbail 			    "Ignoring ipadm config\n"), ifinst);
24186e91bba0SGirish Moodalbail 			return (0);
24196e91bba0SGirish Moodalbail 		}
24206e91bba0SGirish Moodalbail 		status = ipadm_enable_if(ip_handle, ifinst, IPADM_OPT_ACTIVE);
24216e91bba0SGirish Moodalbail 		if (status != IPADM_SUCCESS) {
24226e91bba0SGirish Moodalbail 			rcm_log_message(RCM_ERROR,
24236e91bba0SGirish Moodalbail 			    _("IP: Post-attach failed (%s) Error %s\n"),
24246e91bba0SGirish Moodalbail 			    ifinst, ipadm_status2str(status));
24256e91bba0SGirish Moodalbail 			goto fail;
24266e91bba0SGirish Moodalbail 		}
24276e91bba0SGirish Moodalbail 	}
24286e91bba0SGirish Moodalbail done:
24296e91bba0SGirish Moodalbail 	rcm_log_message(RCM_TRACE1, "IP: if_configure_ipadm(%s) success\n",
24306e91bba0SGirish Moodalbail 	    ifinst);
24316e91bba0SGirish Moodalbail 	return (0);
24326e91bba0SGirish Moodalbail fail:
24336e91bba0SGirish Moodalbail 	return (-1);
24346e91bba0SGirish Moodalbail }
24356e91bba0SGirish Moodalbail 
24366e91bba0SGirish Moodalbail /*
2437e11c3f44Smeem  * isgrouped() - Scans the given config file to see if this interface is
2438e11c3f44Smeem  *	         using IPMP.  Returns B_TRUE or B_FALSE.
2439e11c3f44Smeem  */
2440e11c3f44Smeem static boolean_t
2441e11c3f44Smeem isgrouped(const char *cfgfile)
24427c478bd9Sstevel@tonic-gate {
24437c478bd9Sstevel@tonic-gate 	FILE *fp;
24447c478bd9Sstevel@tonic-gate 	struct stat statb;
2445e11c3f44Smeem 	char *nlp, *line, *token, *lasts, *buf;
2446e11c3f44Smeem 	boolean_t grouped = B_FALSE;
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile);
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 	if (stat(cfgfile, &statb) != 0) {
24517c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1,
24527c478bd9Sstevel@tonic-gate 		    _("IP: No config file(%s)\n"), cfgfile);
2453e11c3f44Smeem 		return (B_FALSE);
24547c478bd9Sstevel@tonic-gate 	}
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	/*
24577c478bd9Sstevel@tonic-gate 	 * We also ignore single-byte config files because the file should
24587c478bd9Sstevel@tonic-gate 	 * always be newline-terminated, so we know there's nothing of
24597c478bd9Sstevel@tonic-gate 	 * interest.  Further, a single-byte file would cause the fgets() loop
24607c478bd9Sstevel@tonic-gate 	 * below to spin forever.
24617c478bd9Sstevel@tonic-gate 	 */
24627c478bd9Sstevel@tonic-gate 	if (statb.st_size <= 1) {
24637c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1,
24647c478bd9Sstevel@tonic-gate 		    _("IP: Empty config file(%s)\n"), cfgfile);
2465e11c3f44Smeem 		return (B_FALSE);
24667c478bd9Sstevel@tonic-gate 	}
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 	if ((fp = fopen(cfgfile, "r")) == NULL) {
24697c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
24707c478bd9Sstevel@tonic-gate 		    _("IP: Cannot open configuration file(%s): %s\n"), cfgfile,
24717c478bd9Sstevel@tonic-gate 		    strerror(errno));
2472e11c3f44Smeem 		return (B_FALSE);
24737c478bd9Sstevel@tonic-gate 	}
24747c478bd9Sstevel@tonic-gate 
2475e11c3f44Smeem 	if ((buf = malloc(statb.st_size)) == NULL) {
24767c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
2477e11c3f44Smeem 		    _("IP: malloc failure(%s): %s\n"), cfgfile,
24787c478bd9Sstevel@tonic-gate 		    strerror(errno));
2479e11c3f44Smeem 		goto out;
24807c478bd9Sstevel@tonic-gate 	}
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 	while (fgets(buf, statb.st_size, fp) != NULL) {
2483e11c3f44Smeem 		if ((nlp = strrchr(buf, '\n')) != NULL)
2484e11c3f44Smeem 			*nlp = '\0';
24857c478bd9Sstevel@tonic-gate 
2486e11c3f44Smeem 		line = buf;
2487e11c3f44Smeem 		while ((token = strtok_r(line, " \t", &lasts)) != NULL) {
2488e11c3f44Smeem 			line = NULL;
2489e11c3f44Smeem 			if (STREQ("group", token) &&
2490e11c3f44Smeem 			    strtok_r(NULL, " \t", &lasts) != NULL) {
2491e11c3f44Smeem 				grouped = B_TRUE;
2492e11c3f44Smeem 				goto out;
24937c478bd9Sstevel@tonic-gate 			}
24947c478bd9Sstevel@tonic-gate 		}
24957c478bd9Sstevel@tonic-gate 	}
2496e11c3f44Smeem out:
24977c478bd9Sstevel@tonic-gate 	free(buf);
24987c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
24997c478bd9Sstevel@tonic-gate 
2500e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s): %d\n", cfgfile,
2501e11c3f44Smeem 	    grouped);
25027c478bd9Sstevel@tonic-gate 
2503e11c3f44Smeem 	return (grouped);
2504e11c3f44Smeem }
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate /*
2507e11c3f44Smeem  * if_config_inst() - Configure an interface instance as specified by the
25087c478bd9Sstevel@tonic-gate  *		    address family af and if it is grouped (ipmp).
25097c478bd9Sstevel@tonic-gate  */
25107c478bd9Sstevel@tonic-gate static int
2511e11c3f44Smeem if_config_inst(const char *ifinst, FILE *hfp, int af, boolean_t ipmp)
25127c478bd9Sstevel@tonic-gate {
2513e11c3f44Smeem 	FILE *ifparsefp;
25147c478bd9Sstevel@tonic-gate 	struct stat statb;
2515e11c3f44Smeem 	char *buf = NULL;
2516e11c3f44Smeem 	char *ifparsebuf = NULL;
2517e11c3f44Smeem 	uint_t ifparsebufsize;
2518e11c3f44Smeem 	const char *fstr;		/* address family string */
2519e11c3f44Smeem 	boolean_t stdif = B_FALSE;
25207c478bd9Sstevel@tonic-gate 
2521e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) ipmp = %d\n",
25227c478bd9Sstevel@tonic-gate 	    ifinst, ipmp);
25237c478bd9Sstevel@tonic-gate 
2524e11c3f44Smeem 	if (fstat(fileno(hfp), &statb) != 0) {
2525e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
2526e11c3f44Smeem 		    _("IP: Cannot fstat file(%s)\n"), ifinst);
2527e11c3f44Smeem 		goto fail;
25287c478bd9Sstevel@tonic-gate 	}
25297c478bd9Sstevel@tonic-gate 
2530e11c3f44Smeem 	switch (af) {
2531e11c3f44Smeem 	case AF_INET:
2532e11c3f44Smeem 		fstr = "inet";
2533e11c3f44Smeem 		break;
2534e11c3f44Smeem 	case AF_INET6:
2535e11c3f44Smeem 		fstr = "inet6";
2536e11c3f44Smeem 		break;
2537e11c3f44Smeem 	default:
2538e11c3f44Smeem 		assert(0);
25397c478bd9Sstevel@tonic-gate 	}
25407c478bd9Sstevel@tonic-gate 
25417c478bd9Sstevel@tonic-gate 	/*
2542e11c3f44Smeem 	 * The hostname file exists; plumb the physical interface.
25437c478bd9Sstevel@tonic-gate 	 */
2544e11c3f44Smeem 	if (!ifconfig(ifinst, fstr, "plumb", B_FALSE))
2545e11c3f44Smeem 		goto fail;
25467c478bd9Sstevel@tonic-gate 
2547e11c3f44Smeem 	/* Skip static configuration if the hostname file is empty */
2548e11c3f44Smeem 	if (statb.st_size <= 1) {
25497c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_TRACE1,
2550e11c3f44Smeem 		    _("IP: Zero size hostname file(%s)\n"), ifinst);
2551e11c3f44Smeem 		goto configured;
25527c478bd9Sstevel@tonic-gate 	}
25537c478bd9Sstevel@tonic-gate 
2554e11c3f44Smeem 	if (fseek(hfp, 0, SEEK_SET) == -1) {
25557c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
2556e11c3f44Smeem 		    _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2557e11c3f44Smeem 		    strerror(errno));
2558e11c3f44Smeem 		goto fail;
25597c478bd9Sstevel@tonic-gate 	}
25607c478bd9Sstevel@tonic-gate 
2561e11c3f44Smeem 	/*
2562e11c3f44Smeem 	 * Allocate the worst-case single-line buffer sizes.  A bit skanky,
2563e11c3f44Smeem 	 * but since hostname files are small, this should suffice.
2564e11c3f44Smeem 	 */
25657c478bd9Sstevel@tonic-gate 	if ((buf = calloc(1, statb.st_size)) == NULL) {
25667c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
25677c478bd9Sstevel@tonic-gate 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2568e11c3f44Smeem 		goto fail;
25697c478bd9Sstevel@tonic-gate 	}
25707c478bd9Sstevel@tonic-gate 
2571e11c3f44Smeem 	ifparsebufsize = statb.st_size + sizeof (SBIN_IFPARSE " -s inet6 ");
2572e11c3f44Smeem 	if ((ifparsebuf = calloc(1, ifparsebufsize)) == NULL) {
2573e11c3f44Smeem 		rcm_log_message(RCM_ERROR,
2574e11c3f44Smeem 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2575e11c3f44Smeem 		goto fail;
25767c478bd9Sstevel@tonic-gate 	}
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	/*
2579e11c3f44Smeem 	 * For IPv4, determine whether the hostname file consists of a single
2580e11c3f44Smeem 	 * line.  We need to handle these specially since they should
2581e11c3f44Smeem 	 * automatically be suffixed with "netmask + broadcast + up".
25827c478bd9Sstevel@tonic-gate 	 */
2583e11c3f44Smeem 	if (af == AF_INET &&
2584e11c3f44Smeem 	    fgets(buf, statb.st_size, hfp) != NULL &&
2585e11c3f44Smeem 	    fgets(buf, statb.st_size, hfp) == NULL) {
2586e11c3f44Smeem 		rcm_log_message(RCM_TRACE1, "IP: one-line hostname file\n");
2587e11c3f44Smeem 		stdif = B_TRUE;
25887c478bd9Sstevel@tonic-gate 	}
2589e11c3f44Smeem 
2590e11c3f44Smeem 	if (fseek(hfp, 0L, SEEK_SET) == -1) {
25917c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
2592e11c3f44Smeem 		    _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
25937c478bd9Sstevel@tonic-gate 		    strerror(errno));
2594e11c3f44Smeem 		goto fail;
25957c478bd9Sstevel@tonic-gate 	}
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate 	/*
2598e11c3f44Smeem 	 * Loop through the file one line at a time and feed it to ifconfig.
2599e11c3f44Smeem 	 * If the interface is using IPMP, then we use /sbin/ifparse -s to
2600e11c3f44Smeem 	 * weed out all of the data addresses, since those are already on the
2601e11c3f44Smeem 	 * IPMP meta-interface.
26027c478bd9Sstevel@tonic-gate 	 */
2603e11c3f44Smeem 	while (fgets(buf, statb.st_size, hfp) != NULL) {
2604e11c3f44Smeem 		if (ntok(buf) == 0)
2605e11c3f44Smeem 			continue;
2606e11c3f44Smeem 
2607e11c3f44Smeem 		if (!ipmp) {
2608e11c3f44Smeem 			(void) ifconfig(ifinst, fstr, buf, stdif);
2609e11c3f44Smeem 			continue;
2610e11c3f44Smeem 		}
2611e11c3f44Smeem 
2612e11c3f44Smeem 		(void) snprintf(ifparsebuf, ifparsebufsize, SBIN_IFPARSE
2613e11c3f44Smeem 		    " -s %s %s", fstr, buf);
2614e11c3f44Smeem 		if ((ifparsefp = popen(ifparsebuf, "r")) == NULL) {
2615e11c3f44Smeem 			rcm_log_message(RCM_ERROR,
2616e11c3f44Smeem 			    _("IP: cannot configure %s: popen \"%s\" "
2617e11c3f44Smeem 			    "failed: %s\n"), ifinst, buf, strerror(errno));
2618e11c3f44Smeem 			goto fail;
2619e11c3f44Smeem 		}
2620e11c3f44Smeem 
2621e11c3f44Smeem 		while (fgets(buf, statb.st_size, ifparsefp) != NULL) {
2622e11c3f44Smeem 			if (ntok(buf) > 0)
2623e11c3f44Smeem 				(void) ifconfig(ifinst, fstr, buf, stdif);
2624e11c3f44Smeem 		}
2625e11c3f44Smeem 
2626e11c3f44Smeem 		if (pclose(ifparsefp) == -1) {
2627e11c3f44Smeem 			rcm_log_message(RCM_ERROR,
2628e11c3f44Smeem 			    _("IP: cannot configure %s: pclose \"%s\" "
2629e11c3f44Smeem 			    "failed: %s\n"), ifinst, buf, strerror(errno));
2630e11c3f44Smeem 			goto fail;
26317c478bd9Sstevel@tonic-gate 		}
26327c478bd9Sstevel@tonic-gate 	}
26337c478bd9Sstevel@tonic-gate 
2634e11c3f44Smeem configured:
2635e11c3f44Smeem 	/*
2636e11c3f44Smeem 	 * Bring up the interface (it may already be up)
2637e11c3f44Smeem 	 *
2638e11c3f44Smeem 	 * Technically, since the boot scripts only unconditionally bring up
2639e11c3f44Smeem 	 * IPv6 interfaces, we should only unconditionally bring up IPv6 here.
2640e11c3f44Smeem 	 * However, if we don't bring up IPv4, and a legacy IPMP configuration
2641e11c3f44Smeem 	 * without test addresses is being used, we will never bring the
2642e11c3f44Smeem 	 * interface up even though we would've at boot.  One fix is to check
2643e11c3f44Smeem 	 * if the IPv4 hostname file contains data addresses that we would've
2644e11c3f44Smeem 	 * brought up, but there's no simple way to do that.  Given that it's
2645e11c3f44Smeem 	 * rare to have persistent IP configuration for an interface that
2646e11c3f44Smeem 	 * leaves it down, we cheap out and always bring it up for IPMP.
2647e11c3f44Smeem 	 */
2648e11c3f44Smeem 	if ((af == AF_INET6 || ipmp) && !ifconfig(ifinst, fstr, "up", B_FALSE))
2649e11c3f44Smeem 		goto fail;
2650e11c3f44Smeem 
2651e11c3f44Smeem 	/*
2652e11c3f44Smeem 	 * For IPv4, if a DHCP configuration file exists, have DHCP configure
2653e11c3f44Smeem 	 * the interface.  As with the boot scripts, this is done after the
2654e11c3f44Smeem 	 * hostname files are processed so that configuration in those files
2655e11c3f44Smeem 	 * (such as IPMP group names) will be applied first.
2656e11c3f44Smeem 	 */
2657e11c3f44Smeem 	if (af == AF_INET) {
2658e11c3f44Smeem 		char dhcpfile[MAXPATHLEN];
2659e11c3f44Smeem 		char *dhcpbuf;
2660e11c3f44Smeem 		off_t i, dhcpsize;
2661e11c3f44Smeem 
2662e11c3f44Smeem 		(void) snprintf(dhcpfile, MAXPATHLEN, DHCPFILE_FMT, ifinst);
2663e11c3f44Smeem 		if (stat(dhcpfile, &statb) == -1)
2664e11c3f44Smeem 			goto out;
2665e11c3f44Smeem 
2666e11c3f44Smeem 		if ((dhcpbuf = copylist(dhcpfile, &dhcpsize)) == NULL) {
2667e11c3f44Smeem 			rcm_log_message(RCM_ERROR, _("IP: cannot read "
2668e11c3f44Smeem 			    "(%s): %s\n"), dhcpfile, strerror(errno));
2669e11c3f44Smeem 			goto fail;
2670e11c3f44Smeem 		}
2671e11c3f44Smeem 
2672e11c3f44Smeem 		/*
2673e11c3f44Smeem 		 * The copylist() API converts \n's to \0's, but we want them
2674e11c3f44Smeem 		 * to be spaces.
2675e11c3f44Smeem 		 */
2676e11c3f44Smeem 		if (dhcpsize > 0) {
2677e11c3f44Smeem 			for (i = 0; i < dhcpsize; i++)
2678e11c3f44Smeem 				if (dhcpbuf[i] == '\0')
2679e11c3f44Smeem 					dhcpbuf[i] = ' ';
2680e11c3f44Smeem 			dhcpbuf[dhcpsize - 1] = '\0';
2681e11c3f44Smeem 		}
2682e11c3f44Smeem 		(void) ifconfig(ifinst, CFG_DHCP_CMD, dhcpbuf, B_FALSE);
2683e11c3f44Smeem 		free(dhcpbuf);
2684e11c3f44Smeem 	}
2685e11c3f44Smeem out:
2686e11c3f44Smeem 	free(ifparsebuf);
26877c478bd9Sstevel@tonic-gate 	free(buf);
2688e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) success\n", ifinst);
26897c478bd9Sstevel@tonic-gate 	return (0);
2690e11c3f44Smeem fail:
2691e11c3f44Smeem 	free(ifparsebuf);
2692e11c3f44Smeem 	free(buf);
2693e11c3f44Smeem 	rcm_log_message(RCM_ERROR, "IP: if_config_inst(%s) failure\n", ifinst);
2694e11c3f44Smeem 	return (-1);
26957c478bd9Sstevel@tonic-gate }
26967c478bd9Sstevel@tonic-gate 
26977c478bd9Sstevel@tonic-gate /*
2698e11c3f44Smeem  * ntok() - count the number of tokens in the provided buffer.
26997c478bd9Sstevel@tonic-gate  */
2700e11c3f44Smeem static uint_t
2701e11c3f44Smeem ntok(const char *cp)
27027c478bd9Sstevel@tonic-gate {
2703e11c3f44Smeem 	uint_t ntok = 0;
27047c478bd9Sstevel@tonic-gate 
2705e11c3f44Smeem 	for (;;) {
27067c478bd9Sstevel@tonic-gate 		while (ISSPACE(*cp))
27077c478bd9Sstevel@tonic-gate 			cp++;
2708e11c3f44Smeem 
27097c478bd9Sstevel@tonic-gate 		if (ISEOL(*cp))
27107c478bd9Sstevel@tonic-gate 			break;
2711e11c3f44Smeem 
27127c478bd9Sstevel@tonic-gate 		do {
2713e11c3f44Smeem 			cp++;
27147c478bd9Sstevel@tonic-gate 		} while (!ISSPACE(*cp) && !ISEOL(*cp));
27157c478bd9Sstevel@tonic-gate 
2716e11c3f44Smeem 		ntok++;
27177c478bd9Sstevel@tonic-gate 	}
2718e11c3f44Smeem 	return (ntok);
2719e11c3f44Smeem }
2720e11c3f44Smeem 
2721e11c3f44Smeem static boolean_t
2722e11c3f44Smeem ifconfig(const char *ifinst, const char *fstr, const char *buf, boolean_t stdif)
2723e11c3f44Smeem {
2724e11c3f44Smeem 	char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
2725e11c3f44Smeem 	int status;
2726e11c3f44Smeem 
2727e11c3f44Smeem 	(void) snprintf(syscmd, sizeof (syscmd), SBIN_IFCONFIG " %s %s %s",
2728e11c3f44Smeem 	    ifinst, fstr, buf);
2729e11c3f44Smeem 
2730e11c3f44Smeem 	if (stdif)
2731e11c3f44Smeem 		(void) strlcat(syscmd, CFG_CMDS_STD, sizeof (syscmd));
2732e11c3f44Smeem 
2733e11c3f44Smeem 	rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd);
2734e11c3f44Smeem 	if ((status = rcm_exec_cmd(syscmd)) != 0) {
2735e11c3f44Smeem 		if (WIFEXITED(status)) {
2736e11c3f44Smeem 			rcm_log_message(RCM_ERROR, _("IP: \"%s\" failed with "
2737e11c3f44Smeem 			    "exit status %d\n"), syscmd, WEXITSTATUS(status));
2738e11c3f44Smeem 		} else {
2739e11c3f44Smeem 			rcm_log_message(RCM_ERROR, _("IP: Error: %s: %s\n"),
2740e11c3f44Smeem 			    syscmd, strerror(errno));
2741e11c3f44Smeem 		}
2742e11c3f44Smeem 		return (B_FALSE);
2743e11c3f44Smeem 	}
2744e11c3f44Smeem 	return (B_TRUE);
27457c478bd9Sstevel@tonic-gate }
27466e91bba0SGirish Moodalbail 
27476e91bba0SGirish Moodalbail /*
27486e91bba0SGirish Moodalbail  * Return TRUE if a writeable /etc/hostname[6].ifname file exists.
27496e91bba0SGirish Moodalbail  */
27506e91bba0SGirish Moodalbail static boolean_t
27516e91bba0SGirish Moodalbail if_hostname_exists(char *ifname, sa_family_t af)
27526e91bba0SGirish Moodalbail {
27536e91bba0SGirish Moodalbail 	char cfgfile[MAXPATHLEN];
27546e91bba0SGirish Moodalbail 
27556e91bba0SGirish Moodalbail 	if (af == AF_INET) {
27566e91bba0SGirish Moodalbail 		(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifname);
27576e91bba0SGirish Moodalbail 		if (access(cfgfile, W_OK|F_OK) == 0)
27586e91bba0SGirish Moodalbail 			return (B_TRUE);
27596e91bba0SGirish Moodalbail 	} else if (af == AF_INET6) {
27606e91bba0SGirish Moodalbail 		(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifname);
27616e91bba0SGirish Moodalbail 		if (access(cfgfile, W_OK|F_OK) == 0)
27626e91bba0SGirish Moodalbail 			return (B_TRUE);
27636e91bba0SGirish Moodalbail 	}
27646e91bba0SGirish Moodalbail 	return (B_FALSE);
27656e91bba0SGirish Moodalbail }
2766