xref: /titanic_50/usr/src/cmd/rcm_daemon/common/ip_rcm.c (revision ff550d0e264b51131fb34e9e83163b348d916640)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * This RCM module adds support to the RCM framework for IP managed
31  * interfaces.
32  */
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <assert.h>
38 #include <string.h>
39 #include <synch.h>
40 #include <libintl.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/socket.h>
46 #include <sys/sockio.h>
47 #include <net/if.h>
48 #include <netinet/in.h>
49 #include <netinet/tcp.h>
50 #include <arpa/inet.h>
51 #include <sys/dlpi.h>
52 #include <stropts.h>
53 #include <strings.h>
54 #include <libdevinfo.h>
55 #include <sys/systeminfo.h>
56 #include <netdb.h>
57 #include <inet/ip.h>
58 
59 #include <ipmp_mpathd.h>
60 #include "rcm_module.h"
61 
62 /*
63  * Definitions
64  */
65 #ifndef lint
66 #define	_(x)	gettext(x)
67 #else
68 #define	_(x)	x
69 #endif
70 
71 /* Some generic well-knowns and defaults used in this module */
72 #define	SLASH_DEV		"/dev"		/* /dev directory */
73 
74 #define	ARP_MOD_NAME		"arp"		/* arp module */
75 #define	IP_MAX_MODS		9		/* max modules pushed on intr */
76 #define	MAX_RECONFIG_SIZE	1024		/* Max. reconfig string size */
77 
78 #define	RCM_NET_PREFIX		"SUNW_network"	/* RCM network name prefix */
79 #define	RCM_NET_RESOURCE_MAX	(13 + LIFNAMSIZ) /* RCM_NET_PREFIX+LIFNAMSIZ */
80 
81 #define	RCM_STR_SUNW_IP		"SUNW_ip/"	/* IP address export prefix */
82 #define	RCM_SIZE_SUNW_IP	9		/* strlen("SUNW_ip/") + 1 */
83 
84 /* ifconfig(1M) */
85 #define	USR_SBIN_IFCONFIG	"/usr/sbin/ifconfig" /* ifconfig command */
86 #define	CFGFILE_FMT_IPV4	"/etc/hostname."  /* IPV4 config file */
87 #define	CFGFILE_FMT_IPV6	"/etc/hostname6." /* IPV6 config file */
88 #define	CFG_CMDS_STD	" netmask + broadcast + up" /* Normal config string */
89 #define	CONFIG_AF_INET		0x1		/* Post-configure IPv4 */
90 #define	CONFIG_AF_INET6		0x2		/* Post-configure IPv6 */
91 #define	MAXLINE			1024		/* Max. line length */
92 #define	MAXARGS			512		/* Max. args in ifconfig cmd */
93 
94 /* Physical interface flags mask */
95 #define	RCM_PIF_FLAGS		(IFF_OFFLINE | IFF_INACTIVE | IFF_FAILED | \
96 				    IFF_STANDBY)
97 
98 /* Some useful macros */
99 #ifndef MAX
100 #define	MAX(a, b)	(((a) > (b))?(a):(b))
101 #endif /* MAX */
102 
103 #ifndef ISSPACE
104 #define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
105 #endif
106 
107 #ifndef	ISEOL
108 #define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
109 #endif
110 
111 #ifndef	STREQ
112 #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
113 #endif
114 
115 #ifndef ADDSPACE
116 #define	ADDSPACE(a)	((void) strcat((a), " "))
117 #endif
118 
119 /* Interface Cache state flags */
120 #define	CACHE_IF_STALE		0x1		/* stale cached data */
121 #define	CACHE_IF_NEW		0x2		/* new cached interface */
122 #define	CACHE_IF_OFFLINED	0x4		/* interface offlined */
123 #define	CACHE_IF_UPDATED	0x8		/* interface props. updated */
124 #define	CACHE_IF_IGNORE		0x10		/* state held elsewhere */
125 
126 /* Network Cache lookup options */
127 #define	CACHE_NO_REFRESH	0x1		/* cache refresh not needed */
128 #define	CACHE_REFRESH		0x2		/* refresh cache */
129 
130 /* RCM IPMP Module specific property definitions */
131 #define	RCM_IPMP_MIN_REDUNDANCY	1		/* default min. redundancy */
132 
133 /* in.mpathd(1M) specifics */
134 #define	MPATHD_MAX_RETRIES	5	/* Max. offline retries */
135 #define	MPATHD_OK		0	/* failback success from mpathd */
136 #define	MPATHD_FAILBACK_TIME	180	/* Time in secs. for mpathd failback */
137 
138 /* Stream module operations */
139 #define	MOD_INSERT		0	/* Insert a mid-stream module */
140 #define	MOD_REMOVE		1	/* Remove a mid-stream module */
141 #define	MOD_CHECK		2	/* Check mid-stream module safety */
142 
143 /* VLAN format support */
144 #define	VLAN_MAX_PPA_ALLOWED	1000
145 #define	VLAN_GET_VID(ppa)	(ppa / VLAN_MAX_PPA_ALLOWED)
146 #define	VLAN_GET_PPA(ppa)	(ppa % VLAN_MAX_PPA_ALLOWED)
147 
148 /* devfsadm attach nvpair values */
149 #define	PROP_NV_DDI_NETWORK	"ddi_network"
150 
151 /*
152  * in.mpathd(1M) message passing formats
153  */
154 typedef struct mpathd_cmd {
155 	uint32_t	cmd_command;		/* message command */
156 	char		cmd_ifname[LIFNAMSIZ];	/* this interface name */
157 	char		cmd_movetoif[LIFNAMSIZ]; /* move to interface */
158 	uint32_t	cmd_min_red;		/* min. redundancy */
159 /* Message passing values for MI_SETOINDEX */
160 #define	from_lifname	cmd_ifname		/* current logical interface */
161 #define	to_pifname	cmd_movetoif		/* new physical interface */
162 #define	addr_family	cmd_min_red		/* address family */
163 } mpathd_cmd_t;
164 
165 /* This is needed since mpathd checks message size for offline */
166 typedef struct mpathd_unoffline {
167 	uint32_t	cmd_command;		/* offline / undo offline */
168 	char		cmd_ifname[LIFNAMSIZ];	/* this interface name */
169 } mpathd_unoffline_t;
170 
171 typedef struct mpathd_response {
172 	uint32_t	resp_sys_errno;		/* system errno */
173 	uint32_t	resp_mpathd_err;	/* mpathd error information */
174 } mpathd_response_t;
175 
176 /*
177  * IP module data types
178  */
179 
180 /* Physical interface representation */
181 typedef struct ip_pif {
182 	char			pi_ifname[LIFNAMSIZ+1];	/* interface name */
183 	char			pi_ifindex;		/* Interface index */
184 	char			pi_grpname[LIFNAMSIZ+1]; /* IPMP group name */
185 	int			pi_style;	/* DLPI provider style */
186 	int			pi_ppa;		/* Phys. point of attachment */
187 	struct ip_lif		*pi_lifs;	/* ptr to logical interfaces */
188 } ip_pif_t;
189 
190 /* Logical interface representation */
191 typedef struct ip_lif
192 {
193 	struct ip_lif		*li_next;	/* ptr to next lif */
194 	struct ip_lif		*li_prev;  	/* previous next ptr */
195 	ip_pif_t		*li_pif;	/* back ptr to phy int */
196 	ushort_t		li_ifnum;	/* interface number */
197 	union {
198 		sa_family_t		family;
199 		struct sockaddr_storage storage;
200 		struct sockaddr_in	ip4;    /* IPv4 */
201 		struct sockaddr_in6	ip6;    /* IPv6 */
202 	} li_addr;
203 	uint64_t		li_ifflags;	/* current IFF_* flags */
204 	uint64_t		li_oldflags;	/* flags prior to offline */
205 	int			li_modcnt;	/* # of modules */
206 	char	*li_modules[IP_MAX_MODS];	/* module list pushed */
207 	char	*li_reconfig;			/* Reconfiguration string */
208 	int32_t			li_cachestate;	/* cache state flags */
209 } ip_lif_t;
210 
211 /* Cache element */
212 typedef struct ip_cache
213 {
214 	struct ip_cache		*ip_next;	/* next cached resource */
215 	struct ip_cache		*ip_prev;	/* prev cached resource */
216 	char			*ip_resource;	/* resource name */
217 	ip_pif_t		*ip_pif;	/* ptr to phy int */
218 	int32_t			ip_ifred;	/* min. redundancy */
219 	int			ip_cachestate;	/* cache state flags */
220 } ip_cache_t;
221 
222 /*
223  * Global cache for network interfaces
224  */
225 static ip_cache_t	cache_head;
226 static ip_cache_t	cache_tail;
227 static mutex_t		cache_lock;
228 static int		events_registered = 0;
229 
230 /*
231  * Global NIC list to be configured after DR-attach
232  */
233 #define	NIL_NULL	((struct ni_list *)0)
234 
235 struct net_interface {
236 	char *type;	/* Name of type of interface  (le, ie, etc.)    */
237 	char *name;	/* Qualified name of interface (le0, ie0, etc.) */
238 };
239 
240 struct ni_list {
241 	struct net_interface *nifp;
242 	struct ni_list *next;
243 };
244 
245 static mutex_t nil_lock;	/* NIC list lock */
246 static int num_ni = 0;		/* Global new interface count */
247 static struct ni_list *nil_head = NIL_NULL;	/* Global new if list */
248 
249 struct devfs_minor_data {
250 	int32_t minor_type;
251 	char *minor_name;
252 	char *minor_node_type;
253 };
254 
255 /*
256  * RCM module interface prototypes
257  */
258 static int ip_register(rcm_handle_t *);
259 static int ip_unregister(rcm_handle_t *);
260 static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t,
261 			char **, char **, nvlist_t *, rcm_info_t **);
262 static int ip_suspend(rcm_handle_t *, char *, id_t,
263 			timespec_t *, uint_t, char **, rcm_info_t **);
264 static int ip_resume(rcm_handle_t *, char *, id_t, uint_t,
265 			char **, rcm_info_t **);
266 static int ip_offline(rcm_handle_t *, char *, id_t, uint_t,
267 			char **, rcm_info_t **);
268 static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
269 			char **, rcm_info_t **);
270 static int ip_remove(rcm_handle_t *, char *, id_t, uint_t,
271 			char **, rcm_info_t **);
272 static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t,
273 			char **, nvlist_t *, rcm_info_t **);
274 
275 /* Module private routines */
276 static void 	free_cache();
277 static int 	update_cache(rcm_handle_t *);
278 static void 	cache_remove(ip_cache_t *);
279 static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char);
280 static void 	free_node(ip_cache_t *);
281 static void 	cache_insert(ip_cache_t *);
282 static char 	*ip_usage(ip_cache_t *);
283 static int 	update_pif(rcm_handle_t *, int, int, struct lifreq *);
284 static int 	ip_ipmp_offline(ip_cache_t *, ip_cache_t *);
285 static int	ip_ipmp_undo_offline(ip_cache_t *);
286 static int	if_cfginfo(ip_cache_t *, uint_t);
287 static int	if_unplumb(ip_cache_t *);
288 static int	if_replumb(ip_cache_t *);
289 static void 	ip_log_err(ip_cache_t *, char **, char *);
290 static int	getdlpi_style(char *);
291 static char	*get_physical_resource(char *);
292 static int	get_ppa(char *);
293 static void	clr_cfg_state(ip_pif_t *);
294 /*LINTED*/
295 static int	if_change_flags(ip_pif_t *, uint64_t, boolean_t);
296 static uint64_t	if_get_flags(ip_pif_t *);
297 static int	mpathd_send_cmd(mpathd_cmd_t *);
298 static int	connect_to_mpathd(int);
299 /*LINTED*/
300 static int	get_lun(char *);
301 /*LINTED*/
302 static void	dump_node(ip_cache_t *);
303 static int	modop(char *, char *, int, char);
304 static int	get_modlist(char *, ip_lif_t *);
305 static int	ip_domux2fd(int *, int *, struct lifreq *);
306 static int	ip_plink(int, int, struct lifreq *);
307 static int	ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
308 			rcm_info_t **);
309 static int	ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
310 			rcm_info_t **);
311 static char 	**ip_get_addrlist(ip_cache_t *);
312 static void	ip_free_addrlist(char **);
313 static void	ip_consumer_notify(rcm_handle_t *, char *, char **, uint_t,
314 			rcm_info_t **);
315 
316 static int process_nvlist(nvlist_t *);
317 static void process_minor(char *, char *, int32_t, struct devfs_minor_data *);
318 static int if_configure(char *);
319 static int isgrouped(char *);
320 static int if_ipmp_config(char *, int, int);
321 static int if_mpathd_configure(char *, char *, int, int);
322 static char *get_mpathd_dest(char *, int);
323 static int if_getcount(int);
324 static void tokenize(char *, char **, char *, int *);
325 
326 
327 /* Module-Private data */
328 static struct rcm_mod_ops ip_ops =
329 {
330 	RCM_MOD_OPS_VERSION,
331 	ip_register,
332 	ip_unregister,
333 	ip_get_info,
334 	ip_suspend,
335 	ip_resume,
336 	ip_offline,
337 	ip_undo_offline,
338 	ip_remove,
339 	NULL,
340 	NULL,
341 	ip_notify_event
342 };
343 
344 /*
345  * rcm_mod_init() - Update registrations, and return the ops structure.
346  */
347 struct rcm_mod_ops *
348 rcm_mod_init(void)
349 {
350 	rcm_log_message(RCM_TRACE1, "IP: mod_init\n");
351 
352 	cache_head.ip_next = &cache_tail;
353 	cache_head.ip_prev = NULL;
354 	cache_tail.ip_prev = &cache_head;
355 	cache_tail.ip_next = NULL;
356 	(void) mutex_init(&cache_lock, NULL, NULL);
357 	(void) mutex_init(&nil_lock, NULL, NULL);
358 
359 	/* Return the ops vectors */
360 	return (&ip_ops);
361 }
362 
363 /*
364  * rcm_mod_info() - Return a string describing this module.
365  */
366 const char *
367 rcm_mod_info(void)
368 {
369 	rcm_log_message(RCM_TRACE1, "IP: mod_info\n");
370 
371 	return ("IP Multipathing module version %I%");
372 }
373 
374 /*
375  * rcm_mod_fini() - Destroy the network interfaces cache.
376  */
377 int
378 rcm_mod_fini(void)
379 {
380 	rcm_log_message(RCM_TRACE1, "IP: mod_fini\n");
381 
382 	free_cache();
383 	(void) mutex_destroy(&nil_lock);
384 	(void) mutex_destroy(&cache_lock);
385 	return (RCM_SUCCESS);
386 }
387 
388 /*
389  * ip_register() - Make sure the cache is properly sync'ed, and its
390  *		 registrations are in order.
391  */
392 static int
393 ip_register(rcm_handle_t *hd)
394 {
395 	rcm_log_message(RCM_TRACE1, "IP: register\n");
396 
397 	/* Guard against bad arguments */
398 	assert(hd != NULL);
399 
400 	if (update_cache(hd) < 0)
401 		return (RCM_FAILURE);
402 
403 	/*
404 	 * Need to register interest in all new resources
405 	 * getting attached, so we get attach event notifications
406 	 */
407 	if (!events_registered) {
408 		if (rcm_register_event(hd, RCM_RESOURCE_NETWORK_NEW, 0, NULL)
409 		    != RCM_SUCCESS) {
410 			rcm_log_message(RCM_ERROR,
411 			    _("IP: failed to register %s\n"),
412 			    RCM_RESOURCE_NETWORK_NEW);
413 			return (RCM_FAILURE);
414 		} else {
415 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
416 			    RCM_RESOURCE_NETWORK_NEW);
417 			events_registered++;
418 		}
419 	}
420 
421 	return (RCM_SUCCESS);
422 }
423 
424 /*
425  * ip_unregister() - Walk the cache, unregistering all the networks.
426  */
427 static int
428 ip_unregister(rcm_handle_t *hd)
429 {
430 	ip_cache_t *probe;
431 
432 	rcm_log_message(RCM_TRACE1, "IP: unregister\n");
433 
434 	/* Guard against bad arguments */
435 	assert(hd != NULL);
436 
437 	/* Walk the cache, unregistering everything */
438 	(void) mutex_lock(&cache_lock);
439 	probe = cache_head.ip_next;
440 	while (probe != &cache_tail) {
441 		if (rcm_unregister_interest(hd, probe->ip_resource, 0)
442 		    != RCM_SUCCESS) {
443 			/* unregister failed for whatever reason */
444 			(void) mutex_unlock(&cache_lock);
445 			return (RCM_FAILURE);
446 		}
447 		cache_remove(probe);
448 		free_node(probe);
449 		probe = cache_head.ip_next;
450 	}
451 	(void) mutex_unlock(&cache_lock);
452 
453 	/*
454 	 * Need to unregister interest in all new resources
455 	 */
456 	if (events_registered) {
457 		if (rcm_unregister_event(hd, RCM_RESOURCE_NETWORK_NEW, 0)
458 		    != RCM_SUCCESS) {
459 			rcm_log_message(RCM_ERROR,
460 			    _("IP: failed to unregister %s\n"),
461 			    RCM_RESOURCE_NETWORK_NEW);
462 			return (RCM_FAILURE);
463 		} else {
464 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
465 			    RCM_RESOURCE_NETWORK_NEW);
466 			events_registered--;
467 		}
468 	}
469 
470 	return (RCM_SUCCESS);
471 }
472 
473 /*
474  * ip_offline() - Offline an interface.
475  */
476 static int
477 ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
478     char **errorp, rcm_info_t **depend_info)
479 {
480 	char *nic;
481 	ip_cache_t *node;
482 	ip_pif_t *pif;
483 	int detachable = 0;
484 	int nofailover = 0;
485 	int ipmp = 0;
486 
487 	rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc);
488 
489 	/* Guard against bad arguments */
490 	assert(hd != NULL);
491 	assert(rsrc != NULL);
492 	assert(id == (id_t)0);
493 	assert(errorp != NULL);
494 	assert(depend_info != NULL);
495 
496 	nic = strrchr(rsrc, '/');
497 	nic = nic ? nic + 1 : rsrc;
498 
499 	/* Lock the cache and lookup the resource */
500 	(void) mutex_lock(&cache_lock);
501 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
502 	if (node == NULL) {
503 		ip_log_err(node, errorp, "Unrecognized resource");
504 		errno = ENOENT;
505 		(void) mutex_unlock(&cache_lock);
506 		return (RCM_SUCCESS);
507 	}
508 
509 	pif = node->ip_pif;
510 
511 	/* Establish default detachability criteria */
512 	if (flags & RCM_FORCE) {
513 		detachable++;
514 	}
515 
516 	/* Check if the interface is an IPMP grouped interface */
517 	if (strcmp(pif->pi_grpname, "")) {
518 		ipmp++;
519 	}
520 
521 	if (if_get_flags(pif) & IFF_NOFAILOVER) {
522 		nofailover++;
523 	}
524 
525 	/*
526 	 * Even if the interface is not in an IPMP group, it's possible that
527 	 * it's still okay to offline it as long as there are higher-level
528 	 * failover mechanisms for the addresses it owns (e.g., clustering).
529 	 * In this case, ip_offlinelist() will return RCM_SUCCESS, and we
530 	 * charge on.
531 	 */
532 	if (!ipmp && !detachable) {
533 		/* Inform consumers of IP addresses being offlined */
534 		if (ip_offlinelist(hd, node, errorp, flags, depend_info) ==
535 		    RCM_SUCCESS) {
536 			rcm_log_message(RCM_DEBUG,
537 				"IP: consumers agree on detach");
538 		} else {
539 			ip_log_err(node, errorp,
540 				"Device consumers prohibit offline");
541 			(void) mutex_unlock(&cache_lock);
542 			return (RCM_FAILURE);
543 		}
544 	}
545 
546 	/*
547 	 * Cannot remove an IPMP interface if IFF_NOFAILOVER is set.
548 	 */
549 	if (ipmp && nofailover) {
550 		/* Interface is part of an IPMP group, and cannot failover */
551 		ip_log_err(node, errorp, "Failover disabled");
552 		errno = EBUSY;
553 		(void) mutex_unlock(&cache_lock);
554 		return (RCM_FAILURE);
555 	}
556 
557 	/* Check if it's a query */
558 	if (flags & RCM_QUERY) {
559 		rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n",
560 		    rsrc);
561 		(void) mutex_unlock(&cache_lock);
562 		return (RCM_SUCCESS);
563 	}
564 
565 	/* Check detachability, save configuration if detachable */
566 	if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) {
567 		node->ip_cachestate |= CACHE_IF_IGNORE;
568 		rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc);
569 		(void) mutex_unlock(&cache_lock);
570 		return (RCM_SUCCESS);
571 	}
572 
573 	/* standalone detachable device */
574 	if (!ipmp) {
575 		if (if_unplumb(node) < 0) {
576 			ip_log_err(node, errorp,
577 			    "Failed to unplumb the device");
578 
579 			errno = EIO;
580 			(void) mutex_unlock(&cache_lock);
581 			return (RCM_FAILURE);
582 		}
583 
584 		node->ip_cachestate |= CACHE_IF_OFFLINED;
585 		rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc);
586 		(void) mutex_unlock(&cache_lock);
587 		return (RCM_SUCCESS);
588 	}
589 
590 	/*
591 	 * This an IPMP interface that can be failed over.
592 	 * Request in.mpathd(1M) to failover the physical interface.
593 	 */
594 
595 	/* Failover to "any", let mpathd determine best failover candidate */
596 	if (ip_ipmp_offline(node, NULL) < 0) {
597 		ip_log_err(node, errorp, "in.mpathd failover failed");
598 		/*
599 		 * Odds are that in.mpathd(1M) could not offline the device
600 		 * because it was the last interface in the group.  However,
601 		 * it's possible that it's still okay to offline it as long as
602 		 * there are higher-level failover mechanisms for the
603 		 * addresses it owns (e.g., clustering).  In this case,
604 		 * ip_offlinelist() will return RCM_SUCCESS, and we charge on.
605 		 *
606 		 * TODO: change ip_ipmp_offline() to return the actual failure
607 		 * from in.mpathd so that we can verify that it did indeed
608 		 * fail with IPMP_EMINRED.
609 		 */
610 		if (!detachable) {
611 			/* Inform consumers of IP addresses being offlined */
612 			if (ip_offlinelist(hd, node, errorp, flags,
613 			    depend_info) == RCM_SUCCESS) {
614 				rcm_log_message(RCM_DEBUG,
615 					"IP: consumers agree on detach");
616 			} else {
617 				ip_log_err(node, errorp,
618 					"Device consumers prohibit offline");
619 				(void) mutex_unlock(&cache_lock);
620 				errno = EBUSY;
621 				return (RCM_FAILURE);
622 			}
623 		}
624 	}
625 
626 	if (if_unplumb(node) < 0) {
627 		rcm_log_message(RCM_ERROR,
628 		    _("IP: Unplumb failed (%s)\n"),
629 		    pif->pi_ifname);
630 
631 		/* Request mpathd to undo the offline */
632 		if (ip_ipmp_undo_offline(node) < 0) {
633 			ip_log_err(node, errorp, "Undo offline failed");
634 			(void) mutex_unlock(&cache_lock);
635 			return (RCM_FAILURE);
636 		}
637 		(void) mutex_unlock(&cache_lock);
638 		return (RCM_FAILURE);
639 	}
640 
641 	node->ip_cachestate |= CACHE_IF_OFFLINED;
642 	rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc);
643 	(void) mutex_unlock(&cache_lock);
644 	return (RCM_SUCCESS);
645 }
646 
647 /*
648  * ip_undo_offline() - Undo offline of a previously offlined device.
649  */
650 /*ARGSUSED*/
651 static int
652 ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
653     char **errorp, rcm_info_t **depend_info)
654 {
655 	ip_cache_t *node;
656 	char *nic;
657 
658 	rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc);
659 
660 	/* Guard against bad arguments */
661 	assert(hd != NULL);
662 	assert(rsrc != NULL);
663 	assert(id == (id_t)0);
664 	assert(errorp != NULL);
665 	assert(depend_info != NULL);
666 
667 	nic = strrchr(rsrc, '/');
668 	nic = nic ? nic + 1 : rsrc;
669 
670 	(void) mutex_lock(&cache_lock);
671 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
672 
673 	if (node == NULL) {
674 		ip_log_err(node, errorp, "No such device");
675 		(void) mutex_unlock(&cache_lock);
676 		errno = ENOENT;
677 		return (RCM_FAILURE);
678 	}
679 
680 	/* Check if no attempt should be made to online the device here */
681 	if (node->ip_cachestate & CACHE_IF_IGNORE) {
682 		node->ip_cachestate &= ~(CACHE_IF_IGNORE);
683 		(void) mutex_unlock(&cache_lock);
684 		return (RCM_SUCCESS);
685 	}
686 
687 	/* Check if the interface was previously offlined */
688 	if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) {
689 		ip_log_err(node, errorp, "Device not offlined");
690 		(void) mutex_unlock(&cache_lock);
691 		errno = ENOTSUP;
692 		return (RCM_FAILURE);
693 	}
694 
695 	if (if_replumb(node) == -1) {
696 		/* re-plumb failed */
697 		ip_log_err(node, errorp, "Replumb failed");
698 		(void) mutex_unlock(&cache_lock);
699 		errno = EIO;
700 		return (RCM_FAILURE);
701 
702 	}
703 
704 	/* Inform consumers about IP addresses being un-offlined */
705 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
706 
707 	node->ip_cachestate &= ~(CACHE_IF_OFFLINED);
708 	rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc);
709 	(void) mutex_unlock(&cache_lock);
710 	return (RCM_SUCCESS);
711 }
712 
713 /*
714  * ip_get_info() - Gather usage information for this resource.
715  */
716 /*ARGSUSED*/
717 int
718 ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
719     char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info)
720 {
721 	ip_cache_t *node;
722 	char *infostr;
723 
724 	/* Guard against bad arguments */
725 	assert(hd != NULL);
726 	assert(rsrc != NULL);
727 	assert(id == (id_t)0);
728 	assert(usagep != NULL);
729 	assert(errorp != NULL);
730 	assert(depend_info != NULL);
731 
732 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc);
733 
734 	(void) mutex_lock(&cache_lock);
735 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
736 	if (!node) {
737 		rcm_log_message(RCM_INFO,
738 		    _("IP: get_info(%s) unrecognized resource\n"), rsrc);
739 		(void) mutex_unlock(&cache_lock);
740 		errno = ENOENT;
741 		return (RCM_FAILURE);
742 	}
743 
744 	infostr = ip_usage(node);
745 
746 	if (infostr == NULL) {
747 		/* most likely malloc failure */
748 		rcm_log_message(RCM_ERROR,
749 		    _("IP: get_info(%s) malloc failure\n"), rsrc);
750 		(void) mutex_unlock(&cache_lock);
751 		errno = ENOMEM;
752 		*errorp = NULL;
753 		return (RCM_FAILURE);
754 	}
755 
756 	/* Set client/role properties */
757 	(void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP");
758 
759 	/* Set usage property, infostr will be freed by caller */
760 	*usagep = infostr;
761 
762 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n",
763 	    rsrc, infostr);
764 
765 	(void) mutex_unlock(&cache_lock);
766 	return (RCM_SUCCESS);
767 }
768 
769 /*
770  * ip_suspend() - Nothing to do, always okay
771  */
772 /*ARGSUSED*/
773 static int
774 ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
775 			uint_t flags, char **errorp, rcm_info_t **depend_info)
776 {
777 	/* Guard against bad arguments */
778 	assert(hd != NULL);
779 	assert(rsrc != NULL);
780 	assert(id == (id_t)0);
781 	assert(interval != NULL);
782 	assert(errorp != NULL);
783 	assert(depend_info != NULL);
784 
785 	rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc);
786 	return (RCM_SUCCESS);
787 }
788 
789 /*
790  * ip_resume() - Nothing to do, always okay
791  */
792 /*ARGSUSED*/
793 static int
794 ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
795 		char **errorp, rcm_info_t ** depend_info)
796 {
797 	/* Guard against bad arguments */
798 	assert(hd != NULL);
799 	assert(rsrc != NULL);
800 	assert(id == (id_t)0);
801 	assert(errorp != NULL);
802 	assert(depend_info != NULL);
803 
804 	rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc);
805 
806 	return (RCM_SUCCESS);
807 }
808 
809 /*
810  * ip_remove() - remove a resource from cache
811  */
812 /*ARGSUSED*/
813 static int
814 ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
815 		char **errorp, rcm_info_t **depend_info)
816 {
817 	ip_cache_t *node;
818 
819 	/* Guard against bad arguments */
820 	assert(hd != NULL);
821 	assert(rsrc != NULL);
822 	assert(id == (id_t)0);
823 	assert(errorp != NULL);
824 	assert(depend_info != NULL);
825 
826 	rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc);
827 
828 	(void) mutex_lock(&cache_lock);
829 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
830 	if (!node) {
831 		rcm_log_message(RCM_INFO,
832 		    _("IP: remove(%s) unrecognized resource\n"), rsrc);
833 		(void) mutex_unlock(&cache_lock);
834 		errno = ENOENT;
835 		return (RCM_FAILURE);
836 	}
837 
838 	/* remove the cached entry for the resource */
839 	cache_remove(node);
840 
841 	(void) mutex_unlock(&cache_lock);
842 	return (RCM_SUCCESS);
843 }
844 
845 /*
846  * ip_notify_event - Project private implementation to receive new resource
847  *		   events. It intercepts all new resource events. If the
848  *		   new resource is a network resource, pass up a notify
849  *		   for it too. The new resource need not be cached, since
850  *		   it is done at register again.
851  */
852 /*ARGSUSED*/
853 static int
854 ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
855 			char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
856 {
857 	struct ni_list	*nilp, *onilp;
858 	struct net_interface *nip;
859 	int		n;
860 
861 	assert(hd != NULL);
862 	assert(rsrc != NULL);
863 	assert(id == (id_t)0);
864 	assert(nvl != NULL);
865 
866 	rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc);
867 
868 	if (!STREQ(rsrc, RCM_RESOURCE_NETWORK_NEW)) {
869 		rcm_log_message(RCM_INFO,
870 		    _("IP: unrecognized event for %s\n"), rsrc);
871 		ip_log_err(NULL, errorp, "unrecognized event");
872 		errno = EINVAL;
873 		return (RCM_FAILURE);
874 	}
875 
876 	/* Update cache to  reflect latest interfaces */
877 	if (update_cache(hd) < 0) {
878 		rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n"));
879 		ip_log_err(NULL, errorp, "Private Cache update failed");
880 		return (RCM_FAILURE);
881 	}
882 
883 	/* Process the nvlist for the event */
884 	if (process_nvlist(nvl) != 0) {
885 		rcm_log_message(RCM_WARNING,
886 		    _("IP: Error processing resource attributes(%s)\n"), rsrc);
887 		rcm_log_message(RCM_WARNING,
888 		    _("IP: One or more devices may not be configured.\n"));
889 		ip_log_err(NULL, errorp, "Error processing device properties");
890 		/* Continue processing interfaces that were valid */
891 	}
892 
893 	(void) mutex_lock(&nil_lock);
894 
895 	/* Configure all new interfaces found */
896 	for (nilp = nil_head, n = 0; n < num_ni; nilp = nilp->next, n++) {
897 		nip = nilp->nifp;
898 		if (if_configure(nip->name) != 0) {
899 			rcm_log_message(RCM_ERROR,
900 			    _("IP: Configuration failed (%s)\n"), nip->name);
901 			ip_log_err(NULL, errorp,
902 			    "Failed configuring one or more IP addresses");
903 			/* continue configuring rest of the interfaces */
904 		}
905 	}
906 
907 	/* Notify all IP address consumers and clean up interface list */
908 	for (nilp = nil_head; nilp; ) {
909 		nip = nilp->nifp;
910 		if (nip != (struct net_interface *)0) {
911 			if (nip->name != 0) {
912 				ip_consumer_notify(hd, nip->name, errorp, flags,
913 					depend_info);
914 				free(nip->name);
915 			}
916 			if (nip->type != 0)
917 				free(nip->type);
918 			free((char *)nip);
919 		}
920 
921 		onilp = nilp;
922 		nilp = nilp->next;
923 		free((char *)onilp);
924 	}
925 
926 	num_ni = 0;		/* reset new if count */
927 	nil_head = NIL_NULL;	/* reset list head */
928 
929 	(void) mutex_unlock(&nil_lock);
930 
931 	rcm_log_message(RCM_TRACE1,
932 	    "IP: notify_event: device configuration complete\n");
933 
934 	return (RCM_SUCCESS);
935 }
936 
937 /*
938  * ip_usage - Determine the usage of a device.  Call with cache_lock held.
939  *	    The returned buffer is owned by caller, and the caller
940  *	    must free it up when done.
941  */
942 static char *
943 ip_usage(ip_cache_t *node)
944 {
945 	ip_lif_t *lif;
946 	int numifs;
947 	char *buf;
948 	char *nic;
949 	const char *fmt;
950 	char *sep;
951 	char addrstr[INET6_ADDRSTRLEN];
952 	int offline = 0;
953 	size_t bufsz;
954 
955 	rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource);
956 
957 	nic = strchr(node->ip_resource, '/');
958 	nic = nic ? nic + 1 : node->ip_resource;
959 
960 	/* TRANSLATION_NOTE: separator used between IP addresses */
961 	sep = _(", ");
962 
963 	numifs = 0;
964 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
965 		if (lif->li_ifflags & IFF_UP) {
966 			numifs++;
967 		}
968 	}
969 
970 	if (node->ip_cachestate & CACHE_IF_OFFLINED) {
971 		offline++;
972 	}
973 
974 	if (!offline && numifs) {
975 		fmt = _("%1$s hosts IP addresses: ");
976 	} else if (offline) {
977 		fmt = _("%1$s offlined");
978 	} else {
979 		fmt = _("%1$s plumbed but down");
980 	}
981 
982 	/* space for addresses and separators, plus message */
983 	bufsz = ((numifs * (INET6_ADDRSTRLEN + strlen(sep))) +
984 	    strlen(fmt) + strlen(nic) + 1);
985 	if ((buf = malloc(bufsz)) == NULL) {
986 		rcm_log_message(RCM_ERROR,
987 		    _("IP: usage(%s) malloc failure(%s)\n"),
988 		    node->ip_resource, strerror(errno));
989 		return (NULL);
990 	}
991 	bzero(buf, bufsz);
992 	(void) sprintf(buf, fmt, nic);
993 
994 	if (offline || (numifs == 0)) {	/* Nothing else to do */
995 		rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
996 		    node->ip_resource, buf);
997 
998 		return (buf);
999 	}
1000 
1001 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1002 
1003 		void *addr;
1004 		int af;
1005 
1006 		if (!(lif->li_ifflags & IFF_UP)) {
1007 			/* ignore interfaces not up */
1008 			continue;
1009 		}
1010 		af = lif->li_addr.family;
1011 		if (af == AF_INET6) {
1012 			addr = &lif->li_addr.ip6.sin6_addr;
1013 		} else if (af == AF_INET) {
1014 			addr = &lif->li_addr.ip4.sin_addr;
1015 		} else {
1016 			rcm_log_message(RCM_DEBUG,
1017 			    "IP: unknown addr family %d, assuming AF_INET\n",
1018 			    af);
1019 			af = AF_INET;
1020 			addr = &lif->li_addr.ip4.sin_addr;
1021 		}
1022 		if (inet_ntop(af, addr, addrstr, INET6_ADDRSTRLEN) == NULL) {
1023 			rcm_log_message(RCM_ERROR,
1024 			    _("IP: inet_ntop: %s\n"), strerror(errno));
1025 			continue;
1026 		}
1027 		rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr);
1028 
1029 		(void) strcat(buf, addrstr);
1030 		numifs--;
1031 		if (numifs > 0) {
1032 			(void) strcat(buf, ", ");
1033 		}
1034 	}
1035 
1036 	rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
1037 	    node->ip_resource, buf);
1038 
1039 	return (buf);
1040 }
1041 
1042 /*
1043  * Cache management routines, all cache management functions should be
1044  * be called with cache_lock held.
1045  */
1046 
1047 /*
1048  * cache_lookup() - Get a cache node for a resource. Supports VLAN interfaces.
1049  *		  Call with cache lock held.
1050  *
1051  * This ensures that the cache is consistent with the system state and
1052  * returns a pointer to the cache element corresponding to the resource.
1053  */
1054 static ip_cache_t *
1055 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
1056 {
1057 	ip_cache_t *probe;
1058 	char *resource;		/* physical resource */
1059 
1060 	rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc);
1061 
1062 	if ((options & CACHE_REFRESH) && (hd != NULL)) {
1063 		/* drop lock since update locks cache again */
1064 		(void) mutex_unlock(&cache_lock);
1065 		(void) update_cache(hd);
1066 		(void) mutex_lock(&cache_lock);
1067 	}
1068 
1069 	if ((resource = get_physical_resource(rsrc)) == NULL) {
1070 		errno = ENOENT;
1071 		return (NULL);
1072 	}
1073 
1074 	probe = cache_head.ip_next;
1075 	while (probe != &cache_tail) {
1076 		if (probe->ip_resource &&
1077 		    STREQ(resource, probe->ip_resource)) {
1078 			rcm_log_message(RCM_TRACE2,
1079 			    "IP: cache lookup success(%s)\n", rsrc);
1080 			free(resource);
1081 			return (probe);
1082 		}
1083 		probe = probe->ip_next;
1084 	}
1085 	free(resource);
1086 	return (NULL);
1087 }
1088 
1089 /*
1090  * free_node - Free a node from the cache
1091  *	     Call with cache_lock held.
1092  */
1093 static void
1094 free_node(ip_cache_t *node)
1095 {
1096 	ip_pif_t *pif;
1097 	ip_lif_t *lif, *tmplif;
1098 
1099 	if (node) {
1100 		if (node->ip_resource) {
1101 			free(node->ip_resource);
1102 		}
1103 
1104 		/* free the pif */
1105 		pif = node->ip_pif;
1106 		if (pif) {
1107 			/* free logical interfaces */
1108 			lif = pif->pi_lifs;
1109 			while (lif) {
1110 				tmplif = lif->li_next;
1111 				free(lif);
1112 				lif = tmplif;
1113 			}
1114 			free(pif);
1115 		}
1116 		free(node);
1117 	}
1118 }
1119 
1120 /*
1121  * cache_insert - Insert a resource node in cache
1122  *		Call with the cache_lock held.
1123  */
1124 static void
1125 cache_insert(ip_cache_t *node)
1126 {
1127 	/* insert at the head for best performance */
1128 	node->ip_next = cache_head.ip_next;
1129 	node->ip_prev = &cache_head;
1130 
1131 	node->ip_next->ip_prev = node;
1132 	node->ip_prev->ip_next = node;
1133 }
1134 
1135 /*
1136  * cache_remove() - Remove a resource node from cache.
1137  *		  Call with the cache_lock held.
1138  */
1139 static void
1140 cache_remove(ip_cache_t *node)
1141 {
1142 	node->ip_next->ip_prev = node->ip_prev;
1143 	node->ip_prev->ip_next = node->ip_next;
1144 	node->ip_next = NULL;
1145 	node->ip_prev = NULL;
1146 }
1147 
1148 /*
1149  * update_pif() - Update physical interface properties
1150  *		Call with cache_lock held
1151  */
1152 /*ARGSUSED*/
1153 static int
1154 update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
1155 {
1156 	char ifname[RCM_NET_RESOURCE_MAX];
1157 	ushort_t ifnumber = 0;
1158 	int ppa;
1159 	char *cp;
1160 	ip_cache_t *probe;
1161 	ip_pif_t pif;
1162 	ip_pif_t *probepif;
1163 	ip_lif_t *probelif;
1164 	struct lifreq lifreq;
1165 	struct sockaddr_storage ifaddr;
1166 	uint64_t ifflags;
1167 	int lif_listed = 0;
1168 
1169 	rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", lifr->lifr_name);
1170 
1171 	/* Determine the interface name and lun number */
1172 	(void) memcpy(&ifname, lifr->lifr_name, sizeof (ifname));
1173 	ifname[sizeof (ifname) - 1] = '\0';
1174 
1175 	/* remove LIF component */
1176 	cp = strchr(ifname, ':');
1177 	if (cp) {
1178 		*cp = 0;
1179 		cp++;
1180 		ifnumber = atoi(cp);
1181 	}
1182 
1183 	(void) memcpy(&pif.pi_ifname, &ifname, sizeof (pif.pi_ifname));
1184 	pif.pi_ifname[sizeof (pif.pi_ifname) - 1] = '\0';
1185 
1186 	/* Determine DLPI style */
1187 	if (getdlpi_style(ifname) == DL_STYLE1) {
1188 		pif.pi_ppa = 0;
1189 		pif.pi_style = DL_STYLE1;
1190 		rcm_log_message(RCM_DEBUG, "IP: DLPI style1 (%s)\n", ifname);
1191 	} else {		/* DLPI style 2 */
1192 		/* Determine the ppa */
1193 		if ((ppa = get_ppa(ifname)) < 0) {
1194 			rcm_log_message(RCM_ERROR,
1195 			    _("IP: get_ppa(%s): %s\n"),
1196 			    ifname, strerror(ENXIO));
1197 			return (-1);
1198 		}
1199 
1200 		pif.pi_style = DL_STYLE2;
1201 		pif.pi_ppa = ppa;
1202 		rcm_log_message(RCM_DEBUG, "IP: DLPI style2 (%s)\n", ifname);
1203 	}
1204 
1205 	/* Get the interface flags */
1206 	(void) strcpy(lifreq.lifr_name, lifr->lifr_name);
1207 	if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
1208 		rcm_log_message(RCM_ERROR,
1209 		    _("IP: SIOCGLIFFLAGS(%s): %s\n"),
1210 		    ifname, strerror(errno));
1211 		return (-1);
1212 	}
1213 	(void) memcpy(&ifflags, &lifreq.lifr_flags, sizeof (ifflags));
1214 
1215 	/* Ignore loopback and multipoint interfaces */
1216 	if (!(ifflags & IFF_MULTICAST) ||
1217 	    (ifflags & IFF_LOOPBACK)) {
1218 		rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n", ifname);
1219 		return (0);
1220 	}
1221 
1222 	/* Get the interface group name for this interface */
1223 	if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) {
1224 		rcm_log_message(RCM_ERROR,
1225 		    _("IP: SIOCGLIFGROUPNAME(%s): %s\n"),
1226 		    lifreq.lifr_name, strerror(errno));
1227 		return (-1);
1228 	}
1229 
1230 	/* copy the group name */
1231 	(void) memcpy(&pif.pi_grpname, &lifreq.lifr_groupname,
1232 	    sizeof (pif.pi_grpname));
1233 	pif.pi_grpname[sizeof (pif.pi_grpname) - 1] = '\0';
1234 
1235 	/* Get the interface address for this interface */
1236 	if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) {
1237 		rcm_log_message(RCM_ERROR,
1238 		    _("IP: SIOCGLIFADDR(%s): %s\n"),
1239 		    lifreq.lifr_name, strerror(errno));
1240 		return (-1);
1241 	}
1242 	(void) memcpy(&ifaddr, &lifreq.lifr_addr, sizeof (ifaddr));
1243 
1244 	/* Get the interface index */
1245 	if (ioctl(sock, SIOCGLIFINDEX, (char *)&lifreq) < 0) {
1246 		rcm_log_message(RCM_ERROR,
1247 		    _("IP: SIOCGLIFINDEX(%s): %s\n"),
1248 		    lifreq.lifr_name, strerror(errno));
1249 		return (-1);
1250 	}
1251 	pif.pi_ifindex = lifreq.lifr_index;
1252 
1253 	/* Search for the interface in our cache */
1254 	(void) snprintf(ifname, sizeof (ifname), "%s/%s", RCM_NET_PREFIX,
1255 	    pif.pi_ifname);
1256 
1257 	probe = cache_lookup(hd, ifname, CACHE_NO_REFRESH);
1258 	if (probe != NULL) {
1259 		probe->ip_cachestate &= ~(CACHE_IF_STALE);
1260 	} else {
1261 		if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) {
1262 			/* malloc errors are bad */
1263 			rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1264 			    strerror(errno));
1265 			return (-1);
1266 		}
1267 
1268 		probe->ip_resource = get_physical_resource(ifname);
1269 		if (!probe->ip_resource) {
1270 			rcm_log_message(RCM_ERROR, _("IP: strdup: %s\n"),
1271 			    strerror(errno));
1272 			free(probe);
1273 			return (-1);
1274 		}
1275 
1276 		probe->ip_pif = NULL;
1277 		probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY;
1278 		probe->ip_cachestate |= CACHE_IF_NEW;
1279 
1280 		cache_insert(probe);
1281 	}
1282 
1283 	probepif = probe->ip_pif;
1284 	if (probepif != NULL) {
1285 		/* Check if lifs need to be updated */
1286 		probelif = probepif->pi_lifs;
1287 		while (probelif != NULL) {
1288 			if ((probelif->li_ifnum == ifnumber) &&
1289 			    (probelif->li_addr.family == ifaddr.ss_family)) {
1290 
1291 				rcm_log_message(RCM_TRACE2,
1292 				    "IP: refreshing lifs for %s, ifnum=%d\n",
1293 				    pif.pi_ifname, probelif->li_ifnum);
1294 
1295 				/* refresh lif properties */
1296 				(void) memcpy(&probelif->li_addr, &ifaddr,
1297 				    sizeof (probelif->li_addr));
1298 
1299 				probelif->li_ifflags = ifflags;
1300 
1301 				lif_listed++;
1302 				probe->ip_cachestate |= CACHE_IF_UPDATED;
1303 				probelif->li_cachestate &= ~(CACHE_IF_STALE);
1304 				break;
1305 			}
1306 			probelif = probelif->li_next;
1307 		}
1308 	}
1309 
1310 	if (probepif == NULL) {
1311 		if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) {
1312 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1313 			    strerror(errno));
1314 			if (probe->ip_pif == NULL) {
1315 				/* we created it, so clean it up */
1316 				free(probe);
1317 			}
1318 			return (-1);
1319 		}
1320 
1321 		probe->ip_pif = probepif;
1322 
1323 		probe->ip_cachestate |= CACHE_IF_UPDATED;
1324 
1325 		/* Save interface name */
1326 		(void) memcpy(&probepif->pi_ifname, &pif.pi_ifname,
1327 		    sizeof (pif.pi_ifname));
1328 	}
1329 
1330 	/* save pif properties */
1331 	probepif->pi_ifindex = pif.pi_ifindex;
1332 	(void) memcpy(&probepif->pi_grpname, &pif.pi_grpname,
1333 	    sizeof (pif.pi_grpname));
1334 	probepif->pi_style = pif.pi_style;
1335 	probepif->pi_ppa = pif.pi_ppa;
1336 
1337 	/* add lif, if this is a lif and it is not in cache */
1338 	if (!lif_listed) {
1339 		rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n",
1340 		    pif.pi_ifname);
1341 
1342 		if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) {
1343 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1344 			    strerror(errno));
1345 			return (-1);
1346 		}
1347 
1348 		/* save lif properties */
1349 		(void) memcpy(&probelif->li_addr, &ifaddr,
1350 		    sizeof (probelif->li_addr));
1351 
1352 		probelif->li_ifnum = ifnumber;
1353 		probelif->li_ifflags = ifflags;
1354 
1355 		/* insert us at the head of the lif list */
1356 		probelif->li_next = probepif->pi_lifs;
1357 		if (probelif->li_next != NULL) {
1358 			probelif->li_next->li_prev = probelif;
1359 		}
1360 		probelif->li_prev = NULL;
1361 		probelif->li_pif = probepif;
1362 
1363 		probepif->pi_lifs = probelif;
1364 		probelif->li_cachestate = CACHE_IF_NEW;
1365 
1366 		probe->ip_cachestate |= CACHE_IF_UPDATED;
1367 	}
1368 
1369 	rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n",
1370 	    probe->ip_resource);
1371 
1372 	return (0);
1373 }
1374 
1375 /*
1376  * update_ipifs() - Determine all network interfaces in the system
1377  *		  Call with cache_lock held
1378  */
1379 static int
1380 update_ipifs(rcm_handle_t *hd, int af)
1381 {
1382 	int sock;
1383 	char *buf;
1384 	struct lifnum lifn;
1385 	struct lifconf lifc;
1386 	struct lifreq *lifrp;
1387 	int i;
1388 
1389 	rcm_log_message(RCM_TRACE2, "IP: update_ipifs\n");
1390 
1391 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
1392 		rcm_log_message(RCM_ERROR,
1393 		    _("IP: failure opening %s socket: %s\n"),
1394 		    af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
1395 		return (-1);
1396 	}
1397 
1398 	lifn.lifn_family = af;
1399 	lifn.lifn_flags = 0;
1400 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
1401 		rcm_log_message(RCM_ERROR,
1402 		    _("IP: SIOCLGIFNUM failed: %s\n"),
1403 		    strerror(errno));
1404 		(void) close(sock);
1405 		return (-1);
1406 	}
1407 
1408 	if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) {
1409 		rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1410 		    strerror(errno));
1411 		(void) close(sock);
1412 		return (-1);
1413 	}
1414 
1415 	lifc.lifc_family = af;
1416 	lifc.lifc_flags = 0;
1417 	lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count;
1418 	lifc.lifc_buf = buf;
1419 
1420 	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
1421 		rcm_log_message(RCM_ERROR,
1422 		    _("IP: SIOCGLIFCONF failed: %s\n"),
1423 		    strerror(errno));
1424 		free(buf);
1425 		(void) close(sock);
1426 		return (-1);
1427 	}
1428 
1429 	/* now we need to search for active interfaces */
1430 	lifrp = lifc.lifc_req;
1431 	for (i = 0; i < lifn.lifn_count; i++) {
1432 		(void) update_pif(hd, af, sock, lifrp);
1433 		lifrp++;
1434 	}
1435 
1436 	free(buf);
1437 	(void) close(sock);
1438 	return (0);
1439 }
1440 
1441 /*
1442  * update_cache() - Update cache with latest interface info
1443  */
1444 static int
1445 update_cache(rcm_handle_t *hd)
1446 {
1447 	ip_cache_t *probe;
1448 	struct ip_lif *lif;
1449 	struct ip_lif *nextlif;
1450 	int rv;
1451 	int i;
1452 
1453 	rcm_log_message(RCM_TRACE2, "IP: update_cache\n");
1454 
1455 	(void) mutex_lock(&cache_lock);
1456 
1457 	/* first we walk the entire cache, marking each entry stale */
1458 	probe = cache_head.ip_next;
1459 	while (probe != &cache_tail) {
1460 		probe->ip_cachestate |= CACHE_IF_STALE;
1461 		if ((probe->ip_pif != NULL) &&
1462 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1463 			while (lif != NULL) {
1464 				lif->li_cachestate |= CACHE_IF_STALE;
1465 				lif = lif->li_next;
1466 			}
1467 		}
1468 		probe = probe->ip_next;
1469 	}
1470 
1471 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n");
1472 	if (update_ipifs(hd, AF_INET) < 0) {
1473 		(void) mutex_unlock(&cache_lock);
1474 		return (-1);
1475 	}
1476 
1477 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n");
1478 	if (update_ipifs(hd, AF_INET6) < 0) {
1479 		(void) mutex_unlock(&cache_lock);
1480 		return (-1);
1481 	}
1482 
1483 	probe = cache_head.ip_next;
1484 	/* unregister devices that are not offlined and still in cache */
1485 	while (probe != &cache_tail) {
1486 		ip_cache_t *freeit;
1487 		if ((probe->ip_pif != NULL) &&
1488 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1489 			/* clear stale lifs */
1490 			while (lif != NULL) {
1491 				if (lif->li_cachestate & CACHE_IF_STALE) {
1492 					nextlif = lif->li_next;
1493 					if (lif->li_prev != NULL)
1494 						lif->li_prev->li_next = nextlif;
1495 					if (nextlif != NULL)
1496 						nextlif->li_prev = lif->li_prev;
1497 					if (probe->ip_pif->pi_lifs == lif)
1498 						probe->ip_pif->pi_lifs =
1499 						    nextlif;
1500 					for (i = 0; i < IP_MAX_MODS; i++) {
1501 						free(lif->li_modules[i]);
1502 					}
1503 					free(lif->li_reconfig);
1504 					free(lif);
1505 					lif = nextlif;
1506 				} else {
1507 					lif = lif->li_next;
1508 				}
1509 			}
1510 		}
1511 		if ((probe->ip_cachestate & CACHE_IF_STALE) &&
1512 		    !(probe->ip_cachestate & CACHE_IF_OFFLINED)) {
1513 			(void) rcm_unregister_interest(hd, probe->ip_resource,
1514 			    0);
1515 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
1516 			    probe->ip_resource);
1517 			freeit = probe;
1518 			probe = probe->ip_next;
1519 			cache_remove(freeit);
1520 			free_node(freeit);
1521 			continue;
1522 		}
1523 
1524 		if (!(probe->ip_cachestate & CACHE_IF_NEW)) {
1525 			probe = probe->ip_next;
1526 			continue;
1527 		}
1528 
1529 		rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL);
1530 		if (rv != RCM_SUCCESS) {
1531 			rcm_log_message(RCM_ERROR,
1532 			    _("IP: failed to register %s\n"),
1533 			    probe->ip_resource);
1534 			(void) mutex_unlock(&cache_lock);
1535 			return (-1);
1536 		} else {
1537 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
1538 			    probe->ip_resource);
1539 			probe->ip_cachestate &= ~(CACHE_IF_NEW);
1540 		}
1541 		probe = probe->ip_next;
1542 	}
1543 
1544 	(void) mutex_unlock(&cache_lock);
1545 	return (0);
1546 }
1547 
1548 /*
1549  * free_cache() - Empty the cache
1550  */
1551 static void
1552 free_cache()
1553 {
1554 	ip_cache_t *probe;
1555 
1556 	rcm_log_message(RCM_TRACE2, "IP: free_cache\n");
1557 
1558 	(void) mutex_lock(&cache_lock);
1559 	probe = cache_head.ip_next;
1560 	while (probe != &cache_tail) {
1561 		cache_remove(probe);
1562 		free_node(probe);
1563 		probe = cache_head.ip_next;
1564 	}
1565 	(void) mutex_unlock(&cache_lock);
1566 }
1567 
1568 /*
1569  * ip_log_err() - RCM error log wrapper
1570  */
1571 static void
1572 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
1573 {
1574 	char *nic = NULL;
1575 	int len;
1576 	const char *errfmt;
1577 	char *error;
1578 
1579 	if ((node != NULL) && (node->ip_pif != NULL) &&
1580 	    (node->ip_pif->pi_ifname != NULL)) {
1581 		nic = strrchr(node->ip_pif->pi_ifname, '/');
1582 		nic = nic ? nic + 1 : node->ip_pif->pi_ifname;
1583 	}
1584 
1585 	if (errorp != NULL)
1586 		*errorp = NULL;
1587 
1588 	if (nic == NULL) {
1589 		rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg);
1590 		errfmt = _("IP: %s");
1591 		len = strlen(errfmt) + strlen(errmsg) + 1;
1592 		if (error = (char *)calloc(1, len)) {
1593 			(void) sprintf(error, errfmt, errmsg);
1594 		}
1595 	} else {
1596 		rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, nic);
1597 		errfmt = _("IP: %s(%s)");
1598 		len = strlen(errfmt) + strlen(errmsg) + strlen(nic) + 1;
1599 		if (error = (char *)calloc(1, len)) {
1600 			(void) sprintf(error, errfmt, errmsg, nic);
1601 		}
1602 	}
1603 
1604 	if (errorp != NULL)
1605 		*errorp = error;
1606 }
1607 
1608 
1609 /*
1610  * if_cfginfo() - Save off the config info for all interfaces
1611  */
1612 static int
1613 if_cfginfo(ip_cache_t *node, uint_t force)
1614 {
1615 	ip_lif_t *lif;
1616 	ip_pif_t *pif;
1617 	int i;
1618 	FILE *fp;
1619 	char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
1620 	char buf[MAX_RECONFIG_SIZE];
1621 
1622 	rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource);
1623 
1624 	pif = node->ip_pif;
1625 	lif = pif->pi_lifs;
1626 
1627 	while (lif != NULL) {
1628 		/* Make a list of modules pushed and save */
1629 		if (lif->li_ifnum == 0) {	/* physical instance */
1630 			if (get_modlist(pif->pi_ifname, lif) == -1) {
1631 				rcm_log_message(RCM_ERROR,
1632 				    _("IP: get modlist error (%s) %s\n"),
1633 				    pif->pi_ifname, strerror(errno));
1634 				(void) clr_cfg_state(pif);
1635 				return (-1);
1636 			}
1637 
1638 			if (!force) {
1639 				/* Look if unknown modules have been inserted */
1640 				for (i = (lif->li_modcnt - 2); i > 0; i--) {
1641 					if (modop(pif->pi_ifname,
1642 					    lif->li_modules[i],
1643 					    i, MOD_CHECK) == -1) {
1644 						rcm_log_message(RCM_ERROR,
1645 						    _("IP: module %s@%d\n"),
1646 						    lif->li_modules[i], i);
1647 						(void) clr_cfg_state(pif);
1648 						return (-1);
1649 					}
1650 				}
1651 			}
1652 
1653 			/* Last module is the device driver, so ignore that */
1654 			for (i = (lif->li_modcnt - 2); i > 0; i--) {
1655 				rcm_log_message(RCM_TRACE2,
1656 				    "IP: modremove Pos = %d, Module = %s \n",
1657 				    i, lif->li_modules[i]);
1658 				if (modop(pif->pi_ifname, lif->li_modules[i],
1659 				    i, MOD_REMOVE) == -1) {
1660 					while (i != (lif->li_modcnt - 2)) {
1661 						if (modop(pif->pi_ifname,
1662 						    lif->li_modules[i],
1663 						    i, MOD_INSERT) == -1) {
1664 							/* Gross error */
1665 							rcm_log_message(
1666 							    RCM_ERROR,
1667 							    _("IP: if_cfginfo"
1668 							    "(%s) %s\n"),
1669 							    pif->pi_ifname,
1670 							    strerror(errno));
1671 							    clr_cfg_state(pif);
1672 							return (-1);
1673 						}
1674 						i++;
1675 					}
1676 					rcm_log_message(
1677 					    RCM_ERROR,
1678 					    _("IP: if_cfginfo(%s): modremove "
1679 					    "%s failed: %s\n"), pif->pi_ifname,
1680 					    lif->li_modules[i],
1681 					    strerror(errno));
1682 					    clr_cfg_state(pif);
1683 					return (-1);
1684 				}
1685 			}
1686 		}
1687 
1688 		/* Save reconfiguration information */
1689 		if (lif->li_ifflags & IFF_IPV4) {
1690 			(void) snprintf(syscmd, sizeof (syscmd),
1691 			    "%s %s:%d configinfo\n", USR_SBIN_IFCONFIG,
1692 			    pif->pi_ifname, lif->li_ifnum);
1693 		} else if (lif->li_ifflags & IFF_IPV6) {
1694 			(void) snprintf(syscmd, sizeof (syscmd),
1695 			    "%s %s:%d inet6 configinfo\n", USR_SBIN_IFCONFIG,
1696 			    pif->pi_ifname, lif->li_ifnum);
1697 		}
1698 		rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd);
1699 
1700 		/* open a pipe to retrieve reconfiguration info */
1701 		if ((fp = popen(syscmd, "r")) == NULL) {
1702 			rcm_log_message(RCM_ERROR,
1703 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1704 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
1705 			(void) clr_cfg_state(pif);
1706 			return (-1);
1707 		}
1708 		bzero(buf, MAX_RECONFIG_SIZE);
1709 
1710 		if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) {
1711 			rcm_log_message(RCM_ERROR,
1712 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1713 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
1714 			(void) pclose(fp);
1715 			(void) clr_cfg_state(pif);
1716 			return (-1);
1717 		}
1718 		(void) pclose(fp);
1719 
1720 		lif->li_reconfig = malloc(strlen(buf)+1);
1721 		if (lif->li_reconfig == NULL) {
1722 			rcm_log_message(RCM_ERROR,
1723 			    _("IP: malloc error (%s) %s\n"),
1724 			    pif->pi_ifname, strerror(errno));
1725 			(void) clr_cfg_state(pif);
1726 			return (-1);
1727 		}
1728 		(void) strcpy(lif->li_reconfig, buf);
1729 		rcm_log_message(RCM_DEBUG,
1730 		    "IP: if_cfginfo: reconfig string(%s:%d) = %s\n",
1731 		    pif->pi_ifname, lif->li_ifnum, lif->li_reconfig);
1732 
1733 		lif = lif->li_next;
1734 	}
1735 
1736 	return (0);
1737 }
1738 
1739 /*
1740  * if_unplumb() - Unplumb the interface
1741  *		Save off the modlist, ifconfig options and unplumb.
1742  *		Fail, if an unknown module lives between IP and driver and
1743  *		force is not set
1744  *		Call with cache_lock held
1745  */
1746 static int
1747 if_unplumb(ip_cache_t *node)
1748 {
1749 	ip_lif_t *lif;
1750 	ip_pif_t *pif;
1751 	int ipv4 = 0, ipv6 = 0;
1752 	char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
1753 
1754 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource);
1755 
1756 	pif = node->ip_pif;
1757 	lif = pif->pi_lifs;
1758 
1759 	while (lif != NULL) {
1760 		if (lif->li_ifflags & IFF_IPV4) {
1761 			ipv4++;
1762 		} else if (lif->li_ifflags & IFF_IPV6) {
1763 			ipv6++;
1764 		} else {
1765 			/* Unlikely case */
1766 			rcm_log_message(RCM_DEBUG,
1767 			    _("IP: Unplumb ignored (%s:%d)\n"),
1768 			    pif->pi_ifname, lif->li_ifnum);
1769 			lif = lif->li_next;
1770 			continue;
1771 		}
1772 		lif = lif->li_next;
1773 	}
1774 
1775 	/* Unplumb the physical interface */
1776 	if (ipv4) {
1777 		rcm_log_message(RCM_TRACE2,
1778 		    "IP: if_unplumb: ifconfig %s unplumb\n", pif->pi_ifname);
1779 		(void) snprintf(syscmd, sizeof (syscmd), "%s %s unplumb\n",
1780 		    USR_SBIN_IFCONFIG, pif->pi_ifname);
1781 		if (rcm_exec_cmd(syscmd) != 0) {
1782 			rcm_log_message(RCM_ERROR,
1783 			    _("IP: Cannot unplumb (%s) %s\n"),
1784 				    pif->pi_ifname, strerror(errno));
1785 			return (-1);
1786 		}
1787 	}
1788 	if (ipv6) {
1789 		rcm_log_message(RCM_TRACE2,
1790 		    "IP: if_unplumb: ifconfig %s inet6 unplumb\n",
1791 		    pif->pi_ifname);
1792 		(void) snprintf(syscmd, sizeof (syscmd),
1793 		    "%s %s inet6 unplumb\n", USR_SBIN_IFCONFIG, pif->pi_ifname);
1794 		if (rcm_exec_cmd(syscmd) != 0) {
1795 			rcm_log_message(RCM_ERROR,
1796 			    _("IP: Cannot unplumb (%s) %s\n"),
1797 				    pif->pi_ifname, strerror(errno));
1798 			return (-1);
1799 		}
1800 	}
1801 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n",
1802 	    node->ip_resource);
1803 
1804 	return (0);
1805 }
1806 
1807 /*
1808  * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface
1809  *		instances and the logical interfaces in order, restoring
1810  *		all ifconfig options
1811  *		Call with cache_lock held
1812  */
1813 static int
1814 if_replumb(ip_cache_t *node)
1815 {
1816 	ip_lif_t *lif;
1817 	ip_pif_t *pif;
1818 	int i;
1819 	char syscmd[LIFNAMSIZ+MAXPATHLEN];	/* must be big enough */
1820 	int max_ipv4 = 0, max_ipv6 = 0;
1821 
1822 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource);
1823 
1824 	/*
1825 	 * Be extra careful about bringing up the interfaces in the
1826 	 * correct order:
1827 	 * - First plumb in the physical interface instances
1828 	 * - modinsert the necessary modules@pos
1829 	 * - Next, add the logical interfaces being careful about
1830 	 *   the order, (follow the cached interface number li_ifnum order)
1831 	 */
1832 
1833 	pif = node->ip_pif;
1834 	lif = pif->pi_lifs;
1835 
1836 	/*
1837 	 * Make a first pass to plumb in physical interfaces and get a count
1838 	 * of the max logical interfaces
1839 	 */
1840 	while (lif != NULL) {
1841 		if (lif->li_ifflags & IFF_IPV4) {
1842 			if (lif->li_ifnum > max_ipv4) {
1843 				max_ipv4 = lif->li_ifnum;
1844 			}
1845 		} else if (lif->li_ifflags & IFF_IPV6) {
1846 			if (lif->li_ifnum > max_ipv6) {
1847 				max_ipv6 = lif->li_ifnum;
1848 			}
1849 		} else {
1850 			/* Unlikely case */
1851 			rcm_log_message(RCM_DEBUG,
1852 			    _("IP: Re-plumb ignored (%s:%d)\n"),
1853 			    pif->pi_ifname, lif->li_ifnum);
1854 			lif = lif->li_next;
1855 			continue;
1856 		}
1857 
1858 		if (lif->li_ifnum == 0) { /* physical interface instance */
1859 			if ((lif->li_ifflags & IFF_NOFAILOVER) ||
1860 			    (strcmp(pif->pi_grpname, "") == 0)) {
1861 				(void) snprintf(syscmd, sizeof (syscmd),
1862 				    "%s %s\n", USR_SBIN_IFCONFIG,
1863 				    lif->li_reconfig);
1864 			} else if (lif->li_ifflags & IFF_IPV4) {
1865 				(void) snprintf(syscmd, sizeof (syscmd),
1866 				    "%s %s inet plumb group %s\n",
1867 				    USR_SBIN_IFCONFIG,
1868 				    pif->pi_ifname, pif->pi_grpname);
1869 			} else if (lif->li_ifflags & IFF_IPV6) {
1870 				(void) snprintf(syscmd, sizeof (syscmd),
1871 				    "%s %s inet6 plumb group %s\n",
1872 				    USR_SBIN_IFCONFIG,
1873 				    pif->pi_ifname, pif->pi_grpname);
1874 			}
1875 
1876 			rcm_log_message(RCM_TRACE2,
1877 			    "IP: if_replumb: %s\n", syscmd);
1878 			if (rcm_exec_cmd(syscmd) != 0) {
1879 				rcm_log_message(RCM_ERROR,
1880 				    _("IP: Cannot plumb (%s) %s\n"),
1881 				    pif->pi_ifname, strerror(errno));
1882 				return (-1);
1883 			}
1884 
1885 			rcm_log_message(RCM_TRACE2,
1886 			    "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt);
1887 			/* modinsert modules in order, ignore driver(last) */
1888 			for (i = 0; i < (lif->li_modcnt - 1); i++) {
1889 				rcm_log_message(RCM_TRACE2,
1890 				    "IP: modinsert: Pos = %d Mod = %s\n",
1891 				    i, lif->li_modules[i]);
1892 				if (modop(pif->pi_ifname, lif->li_modules[i], i,
1893 				    MOD_INSERT) == -1) {
1894 					rcm_log_message(RCM_ERROR,
1895 					    _("IP: modinsert error(%s)\n"),
1896 					    pif->pi_ifname);
1897 					return (-1);
1898 				}
1899 			}
1900 		}
1901 
1902 		lif = lif->li_next;
1903 	}
1904 
1905 	/* Now, add all the logical interfaces in the correct order */
1906 	for (i = 1; i <= MAX(max_ipv6, max_ipv4); i++) {
1907 		/* reset lif through every iteration */
1908 		lif = pif->pi_lifs;
1909 		while (lif != NULL) {
1910 			if (((lif->li_ifflags & IFF_NOFAILOVER) ||
1911 			    (strcmp(pif->pi_grpname, "") == 0)) &&
1912 			    (lif->li_ifnum == i)) {
1913 				/* Plumb in the logical interface */
1914 				(void) snprintf(syscmd, sizeof (syscmd),
1915 				    "%s %s\n", USR_SBIN_IFCONFIG,
1916 				    lif->li_reconfig);
1917 				rcm_log_message(RCM_TRACE2,
1918 				    "IP: if_replumb: %s\n", syscmd);
1919 				if (rcm_exec_cmd(syscmd) != 0) {
1920 					rcm_log_message(RCM_ERROR,
1921 					    _("IP: Cannot addif (%s:%d) "
1922 						"%s\n"),
1923 					    pif->pi_ifname, i, strerror(errno));
1924 					return (-1);
1925 				}
1926 			}
1927 			lif = lif->li_next;
1928 		}
1929 	}
1930 
1931 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n",
1932 	    node->ip_resource);
1933 
1934 	return (0);
1935 }
1936 
1937 /*
1938  * clr_cfg_state() - Cleanup after errors in unplumb
1939  */
1940 static void
1941 clr_cfg_state(ip_pif_t *pif)
1942 {
1943 	ip_lif_t *lif;
1944 	int i;
1945 
1946 	lif = pif->pi_lifs;
1947 
1948 	while (lif != NULL) {
1949 		lif->li_modcnt = 0;
1950 		free(lif->li_reconfig);
1951 		lif->li_reconfig = NULL;
1952 		for (i = 0; i < IP_MAX_MODS; i++) {
1953 			free(lif->li_modules[i]);
1954 			lif->li_modules[i] = NULL;
1955 		}
1956 		lif = lif->li_next;
1957 	}
1958 }
1959 
1960 /*
1961  * ip_ipmp_offline() - Failover from if_from to if_to using a
1962  *		     minimum redudancy of min_red. This uses IPMPs
1963  *		     "offline" mechanism to achieve the failover.
1964  */
1965 static int
1966 ip_ipmp_offline(ip_cache_t *if_from, ip_cache_t *if_to)
1967 {
1968 	mpathd_cmd_t mpdcmd;
1969 
1970 	if ((if_from == NULL) || (if_from->ip_pif == NULL) ||
1971 	    (if_from->ip_pif->pi_ifname == NULL)) {
1972 		return (-1);
1973 	}
1974 
1975 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n");
1976 
1977 	mpdcmd.cmd_command = MI_OFFLINE;
1978 	(void) strcpy(mpdcmd.cmd_ifname, if_from->ip_pif->pi_ifname);
1979 
1980 	if ((if_to != NULL) && (if_to->ip_pif != NULL) &&
1981 	    (if_to->ip_pif->pi_ifname != NULL)) {
1982 		rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline (%s)->(%s)\n",
1983 		    if_from->ip_pif->pi_ifname, if_to->ip_pif->pi_ifname);
1984 		(void) strncpy(mpdcmd.cmd_movetoif, if_to->ip_pif->pi_ifname,
1985 		    sizeof (mpdcmd.cmd_movetoif));
1986 		mpdcmd.cmd_movetoif[sizeof (mpdcmd.cmd_movetoif) - 1] = '\0';
1987 	} else {
1988 		rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline (%s)->(any)\n",
1989 		    if_from->ip_pif->pi_ifname);
1990 		(void) strcpy(mpdcmd.cmd_movetoif, "");	/* signifies any */
1991 	}
1992 	mpdcmd.cmd_min_red = if_from->ip_ifred;
1993 
1994 	if (mpathd_send_cmd(&mpdcmd) < 0) {
1995 		rcm_log_message(RCM_ERROR,
1996 		    _("IP: mpathd offline error: %s\n"),
1997 		    strerror(errno));
1998 		return (-1);
1999 	}
2000 
2001 	rcm_log_message(RCM_TRACE1, "IP: ipmp offline success\n");
2002 	return (0);
2003 }
2004 
2005 /*
2006  * ip_ipmp_undo_offline() - Undo prior offline of the interface.
2007  *			  This uses IPMPs "undo offline" feature.
2008  */
2009 static int
2010 ip_ipmp_undo_offline(ip_cache_t *node)
2011 {
2012 	mpathd_cmd_t mpdcmd;
2013 
2014 	mpdcmd.cmd_command = MI_UNDO_OFFLINE;
2015 	(void) strcpy(mpdcmd.cmd_ifname, node->ip_pif->pi_ifname);
2016 
2017 	if (mpathd_send_cmd(&mpdcmd) < 0) {
2018 		rcm_log_message(RCM_ERROR,
2019 		    _("IP: mpathd error: %s\n"),
2020 		    strerror(errno));
2021 		return (-1);
2022 	}
2023 
2024 	rcm_log_message(RCM_TRACE1, "IP: ipmp undo offline success\n");
2025 	return (0);
2026 }
2027 
2028 /*
2029  * getdlpi_style() - Determine the DLPI provider style of the interface
2030  */
2031 static int
2032 getdlpi_style(char *ifname)
2033 {
2034 	int local_fd;
2035 	char devname[RCM_NET_RESOURCE_MAX];
2036 
2037 	(void) snprintf(devname, sizeof (devname), "%s/%s", SLASH_DEV, ifname);
2038 
2039 	/* First try DLPI style 1 */
2040 	if ((local_fd = open(devname, O_RDWR)) != -1) {
2041 		(void) close(local_fd);
2042 		return (DL_STYLE1);
2043 	}
2044 
2045 	return (DL_STYLE2);
2046 }
2047 
2048 /*
2049  * get_ppa() - Determine the ppa for an interface, DLPI style 2 only
2050  */
2051 static int
2052 get_ppa(char *rsrc)
2053 {
2054 	int i;
2055 	uint_t p = 0;
2056 	unsigned int m = 1;
2057 
2058 	i = strlen(rsrc) - 1;
2059 	while (i >= 0 && '0' <= rsrc[i] && rsrc[i] <= '9') {
2060 		p += (rsrc[i] - '0')*m;
2061 		m *= 10;
2062 		i--;
2063 	}
2064 	if (m == 1) {
2065 		return (-1);
2066 	}
2067 	return (VLAN_GET_PPA(p)); /* VLAN support */
2068 }
2069 
2070 /*
2071  * get_lun() - Determine the logical interface number
2072  */
2073 static int
2074 get_lun(char *rsrc)
2075 {
2076 	char resource[RCM_NET_RESOURCE_MAX];
2077 	char *cp;
2078 
2079 	(void) strcpy(resource, rsrc);
2080 
2081 	/* remove LIF component */
2082 	cp = strchr(resource, ':');
2083 	if (cp) {
2084 		cp++;
2085 		return (atoi(cp));
2086 	}
2087 
2088 	return (0);
2089 }
2090 
2091 /*
2092  * get_physical_resource() - Determine the actual physical interface name.
2093  *			   Supports VLAN interfaces.
2094  *			   Caller must free the malloced space for the string.
2095  */
2096 static char *
2097 get_physical_resource(char *rsrc)
2098 {
2099 	char *resource;
2100 	char *ifname;
2101 	char *nic;
2102 	int ppa;
2103 
2104 	resource = (char *)malloc(strlen(rsrc) + 1);
2105 	if (resource == NULL) {
2106 		rcm_log_message(RCM_ERROR,
2107 		    _("IP: malloc error(%s): %s\n"), strerror(errno), rsrc);
2108 		return (NULL);
2109 	}
2110 	(void) strcpy(resource, rsrc);
2111 
2112 	/* remove LIF component if any */
2113 	nic = strchr(resource, ':');
2114 	if (nic) {
2115 		*nic = 0;
2116 	}
2117 
2118 	ppa = get_ppa(resource);
2119 
2120 	/* Determine device name */
2121 	nic = resource;
2122 	while (nic++) {
2123 		if (('0' <= *nic) && (*nic <= '9')) {
2124 			*nic = 0;
2125 			break;
2126 		}
2127 	}
2128 
2129 	ifname = (char *)malloc(RCM_NET_RESOURCE_MAX);
2130 	if (ifname == NULL) {
2131 		rcm_log_message(RCM_ERROR,
2132 		    _("IP: malloc error(%s): %s\n"), strerror(errno), rsrc);
2133 		free(resource);
2134 		return (NULL);
2135 	}
2136 
2137 	if (ppa < 0) {
2138 		/* This could be a network group */
2139 		(void) snprintf(ifname, RCM_NET_RESOURCE_MAX, "%s", resource);
2140 	} else {
2141 		(void) snprintf(ifname, RCM_NET_RESOURCE_MAX, "%s%d",
2142 		    resource, ppa);
2143 	}
2144 
2145 	free(resource);
2146 	return (ifname);
2147 }
2148 
2149 /*
2150  * if_change_flags() - set/clear the flag specified for the physical interface
2151  *		     Call with cache_lock held
2152  */
2153 static int
2154 if_change_flags(ip_pif_t *pif, uint64_t flags, boolean_t set)
2155 {
2156 	int sock;
2157 	struct lifreq lifr;
2158 	ip_lif_t *lif;
2159 
2160 	if (!(flags & RCM_PIF_FLAGS)) {
2161 		rcm_log_message(RCM_DEBUG,
2162 		    "IP: if_change_flags: Not a physical interface flag\n");
2163 		return (-1);
2164 	}
2165 
2166 	/* IPv4 is ok, since we only manipulate physical interface flags */
2167 	if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
2168 		rcm_log_message(RCM_ERROR,
2169 		    _("IPv4 socket open: %s\n"), strerror(errno));
2170 		return (-1);
2171 	}
2172 
2173 	/*
2174 	 * Get the current flags from the kernel, and set/clear the
2175 	 * desired phyint flags.
2176 	 */
2177 	(void) strncpy(lifr.lifr_name, pif->pi_ifname, sizeof (lifr.lifr_name));
2178 	lifr.lifr_name[sizeof (lifr.lifr_name) - 1] = '\0';
2179 	if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifr) < 0) {
2180 		rcm_log_message(RCM_DEBUG,
2181 		    "ioctl SIOCGLIFFLAGS: %s\n", strerror(errno));
2182 		(void) close(sock);
2183 		return (-1);
2184 	}
2185 	if (set)
2186 		lifr.lifr_flags |= flags;
2187 	else
2188 		lifr.lifr_flags &= ~flags;
2189 	if (ioctl(sock, SIOCSLIFFLAGS, (char *)&lifr) < 0) {
2190 		rcm_log_message(RCM_DEBUG,
2191 		    "ioctl SIOCSLIFFLAGS: %s\n", strerror(errno));
2192 		(void) close(sock);
2193 		return (-1);
2194 	}
2195 
2196 	(void) close(sock);
2197 
2198 	/* Keep cached flags consistent.  */
2199 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
2200 		if (lif->li_ifnum == 0) {
2201 			if (set)
2202 				lif->li_ifflags |= flags;
2203 			else
2204 				lif->li_ifflags &= ~flags;
2205 		}
2206 	}
2207 
2208 	return (0);
2209 }
2210 
2211 /*
2212  * if_get_flags() - Return the cached physical interface flags
2213  *		  Call with cache_lock held
2214  */
2215 static uint64_t
2216 if_get_flags(ip_pif_t *pif)
2217 {
2218 	ip_lif_t *lif;
2219 
2220 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
2221 		if (lif->li_ifnum == 0) {
2222 			return (lif->li_ifflags & RCM_PIF_FLAGS);
2223 		}
2224 	}
2225 	return (0);
2226 }
2227 
2228 /*
2229  * mpathd_send_cmd() - Sends the command to in.mpathd.
2230  */
2231 static int
2232 mpathd_send_cmd(mpathd_cmd_t *mpd)
2233 {
2234 	mpathd_unoffline_t mpc;
2235 	struct mpathd_response mpr;
2236 	int i;
2237 	int s;
2238 
2239 	rcm_log_message(RCM_TRACE1, "IP: mpathd_send_cmd \n");
2240 
2241 	for (i = 0; i < MPATHD_MAX_RETRIES; i++) {
2242 		s = connect_to_mpathd(AF_INET);
2243 		if (s == -1) {
2244 			s = connect_to_mpathd(AF_INET6);
2245 			if (s == -1) {
2246 				rcm_log_message(RCM_ERROR,
2247 				    _("IP: Cannot talk to mpathd\n"));
2248 				return (-1);
2249 			}
2250 		}
2251 		switch (mpd->cmd_command) {
2252 		case MI_OFFLINE :
2253 			rcm_log_message(RCM_TRACE1, "IP: MI_OFFLINE: "
2254 			    "(%s)->(%s) redundancy = %d\n", mpd->cmd_ifname,
2255 			    mpd->cmd_movetoif, mpd->cmd_min_red);
2256 
2257 			if (write(s, mpd, sizeof (mpathd_cmd_t)) !=
2258 			    sizeof (mpathd_cmd_t)) {
2259 				rcm_log_message(RCM_ERROR,
2260 				    _("IP: mpathd write: %s\n"),
2261 				    strerror(errno));
2262 				(void) close(s);
2263 				return (-1);
2264 			}
2265 			break;
2266 
2267 		case MI_SETOINDEX :
2268 			rcm_log_message(RCM_TRACE1, "IP: MI_SETOINDEX: "
2269 			    "(%s)->(%s) family = %d\n", mpd->from_lifname,
2270 			    mpd->to_pifname, mpd->addr_family);
2271 
2272 			if (write(s, mpd, sizeof (mpathd_cmd_t)) !=
2273 			    sizeof (mpathd_cmd_t)) {
2274 				rcm_log_message(RCM_ERROR,
2275 				    _("IP: mpathd write: %s\n"),
2276 				    strerror(errno));
2277 				(void) close(s);
2278 				return (-1);
2279 			}
2280 			break;
2281 
2282 		case MI_UNDO_OFFLINE:
2283 			/* mpathd checks for exact size of the message */
2284 			mpc.cmd_command = mpd->cmd_command;
2285 			(void) strcpy(mpc.cmd_ifname, mpd->cmd_ifname);
2286 
2287 			rcm_log_message(RCM_TRACE1, "IP: MI_UNDO_OFFLINE: "
2288 			    "(%s)\n", mpd->cmd_ifname);
2289 
2290 			if (write(s, &mpc, sizeof (mpathd_unoffline_t)) !=
2291 			    sizeof (mpathd_unoffline_t)) {
2292 				rcm_log_message(RCM_ERROR,
2293 				    _("IP: mpathd write: %s\n"),
2294 				    strerror(errno));
2295 				(void) close(s);
2296 				return (-1);
2297 			}
2298 			break;
2299 		default :
2300 			rcm_log_message(RCM_ERROR,
2301 			    _("IP: unsupported mpathd command\n"));
2302 			(void) close(s);
2303 			return (-1);
2304 		}
2305 
2306 		bzero(&mpr, sizeof (struct mpathd_response));
2307 		/* Read the result from mpathd */
2308 		if (read(s, &mpr, sizeof (struct mpathd_response)) !=
2309 		    sizeof (struct mpathd_response)) {
2310 			rcm_log_message(RCM_ERROR,
2311 			    _("IP: mpathd read : %s\n"), strerror(errno));
2312 			(void) close(s);
2313 			return (-1);
2314 		}
2315 
2316 		(void) close(s);
2317 		if (mpr.resp_mpathd_err == 0) {
2318 			rcm_log_message(RCM_TRACE1,
2319 			    "IP: mpathd_send_cmd success\n");
2320 			return (0);			/* Successful */
2321 		}
2322 
2323 		if (mpr.resp_mpathd_err == MPATHD_SYS_ERROR) {
2324 			if (mpr.resp_sys_errno == EAGAIN) {
2325 				(void) sleep(1);
2326 				rcm_log_message(RCM_DEBUG,
2327 				    _("IP: mpathd retrying\n"));
2328 				continue;		/* Retry */
2329 			}
2330 			errno = mpr.resp_sys_errno;
2331 			rcm_log_message(RCM_WARNING,
2332 			    _("IP: mpathd_send_cmd error: %s\n"),
2333 			    strerror(errno));
2334 		} else if (mpr.resp_mpathd_err == MPATHD_MIN_RED_ERROR) {
2335 			errno = EIO;
2336 			rcm_log_message(RCM_ERROR, _("IP: in.mpathd(1M): "
2337 			    "Minimum redundancy not met\n"));
2338 		} else {
2339 			rcm_log_message(RCM_ERROR,
2340 			    _("IP: mpathd_send_cmd error\n"));
2341 		}
2342 		/* retry */
2343 	}
2344 
2345 	rcm_log_message(RCM_ERROR,
2346 	    _("IP: mpathd_send_cmd failed %d retries\n"), MPATHD_MAX_RETRIES);
2347 	return (-1);
2348 }
2349 
2350 /*
2351  * Returns -1 on failure. Returns the socket file descriptor on
2352  * success.
2353  */
2354 static int
2355 connect_to_mpathd(int family)
2356 {
2357 	int s;
2358 	struct sockaddr_storage ss;
2359 	struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
2360 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
2361 	struct in6_addr loopback_addr = IN6ADDR_LOOPBACK_INIT;
2362 	int addrlen;
2363 	int ret;
2364 	int on;
2365 
2366 	rcm_log_message(RCM_TRACE1, "IP: connect_to_mpathd\n");
2367 
2368 	s = socket(family, SOCK_STREAM, 0);
2369 	if (s < 0) {
2370 		rcm_log_message(RCM_ERROR,
2371 		    _("IP: mpathd socket: %s\n"), strerror(errno));
2372 		return (-1);
2373 	}
2374 	bzero((char *)&ss, sizeof (ss));
2375 	ss.ss_family = family;
2376 	/*
2377 	 * Need to bind to a privelged port. For non-root, this
2378 	 * will fail. in.mpathd verifies that only commands coming
2379 	 * from priveleged ports succeed so that the ordinary user
2380 	 * can't issue offline commands.
2381 	 */
2382 	on = 1;
2383 	if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on,
2384 	    sizeof (on)) < 0) {
2385 		rcm_log_message(RCM_ERROR,
2386 		    _("IP: mpathd setsockopt: TCP_ANONPRIVBIND: %s\n"),
2387 		    strerror(errno));
2388 		return (-1);
2389 	}
2390 	switch (family) {
2391 	case AF_INET:
2392 		sin->sin_port = 0;
2393 		sin->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
2394 		addrlen = sizeof (struct sockaddr_in);
2395 		break;
2396 	case AF_INET6:
2397 		sin6->sin6_port = 0;
2398 		sin6->sin6_addr = loopback_addr;
2399 		addrlen = sizeof (struct sockaddr_in6);
2400 		break;
2401 	}
2402 	ret = bind(s, (struct sockaddr *)&ss, addrlen);
2403 	if (ret != 0) {
2404 		rcm_log_message(RCM_ERROR,
2405 		    _("IP: mpathd bind: %s\n"), strerror(errno));
2406 		return (-1);
2407 	}
2408 	switch (family) {
2409 	case AF_INET:
2410 		sin->sin_port = htons(MPATHD_PORT);
2411 		break;
2412 	case AF_INET6:
2413 		sin6->sin6_port = htons(MPATHD_PORT);
2414 		break;
2415 	}
2416 	ret = connect(s, (struct sockaddr *)&ss, addrlen);
2417 	if (ret != 0) {
2418 		if (errno == ECONNREFUSED) {
2419 			/* in.mpathd is not running, start it */
2420 			if (rcm_exec_cmd(MPATHD_PATH) == -1) {
2421 				rcm_log_message(RCM_ERROR,
2422 				    _("IP: mpathd exec: %s\n"),
2423 				    strerror(errno));
2424 				return (-1);
2425 			}
2426 			ret = connect(s, (struct sockaddr *)&ss, addrlen);
2427 		}
2428 		if (ret != 0) {
2429 			rcm_log_message(RCM_ERROR,
2430 			    _("IP: mpathd connect: %s\n"), strerror(errno));
2431 			return (-1);
2432 		}
2433 	}
2434 	on = 0;
2435 	if (setsockopt(s, IPPROTO_TCP, TCP_ANONPRIVBIND, &on,
2436 	    sizeof (on)) < 0) {
2437 		rcm_log_message(RCM_ERROR,
2438 		    _("IP: mpathd setsockopt TCP_ANONPRIVBIND: %s\n"),
2439 		    strerror(errno));
2440 		return (-1);
2441 	}
2442 
2443 	rcm_log_message(RCM_TRACE1, "IP: connect_to_mpathd success\n");
2444 
2445 	return (s);
2446 }
2447 
2448 /*
2449  * modop() - Remove/insert a module
2450  */
2451 static int
2452 modop(char *name, char *arg, int pos, char op)
2453 {
2454 	char syscmd[LIFNAMSIZ+MAXPATHLEN];	/* must be big enough */
2455 
2456 	rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name);
2457 
2458 	/* Nothing to do with "ip", "arp" */
2459 	if ((arg == NULL) || (strcmp(arg, "") == 0) ||
2460 	    STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) {
2461 		rcm_log_message(RCM_TRACE1, "IP: modop success\n");
2462 		return (0);
2463 	}
2464 
2465 	if (op == MOD_CHECK) {
2466 		/*
2467 		 * No known good modules (yet) apart from ip and arp
2468 		 * which are handled above
2469 		 */
2470 		return (-1);
2471 	}
2472 
2473 	if (op == MOD_REMOVE) {
2474 		(void) snprintf(syscmd, sizeof (syscmd),
2475 		    "%s %s modremove %s@%d\n", USR_SBIN_IFCONFIG, name, arg,
2476 		    pos);
2477 	} else if (op == MOD_INSERT) {
2478 		(void) snprintf(syscmd, sizeof (syscmd),
2479 		    "%s %s modinsert %s@%d\n", USR_SBIN_IFCONFIG, name, arg,
2480 		    pos);
2481 	} else {
2482 		rcm_log_message(RCM_ERROR,
2483 		    _("IP: modop(%s): unknown operation\n"), name);
2484 		return (-1);
2485 	}
2486 
2487 	rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd);
2488 	if (rcm_exec_cmd(syscmd) == -1) {
2489 		rcm_log_message(RCM_ERROR,
2490 		    _("IP: modop(%s): %s\n"), name, strerror(errno));
2491 		return (-1);
2492 	}
2493 
2494 	rcm_log_message(RCM_TRACE1, "IP: modop success\n");
2495 	return (0);
2496 }
2497 
2498 /*
2499  * get_modlist() - return a list of pushed mid-stream modules
2500  *		 Required memory is malloced to construct the list,
2501  *		 Caller must free this memory list
2502  *		 Call with cache_lock held
2503  */
2504 static int
2505 get_modlist(char *name, ip_lif_t *lif)
2506 {
2507 	int udp_fd;
2508 	int fd;
2509 	int i;
2510 	int num_mods;
2511 	struct lifreq lifr;
2512 	struct str_list strlist;
2513 
2514 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name);
2515 
2516 	(void) strncpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
2517 	lifr.lifr_flags = lif->li_ifflags;
2518 	if (ip_domux2fd(&udp_fd, &fd, &lifr) < 0) {
2519 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name);
2520 		return (-1);
2521 	}
2522 
2523 	if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) {
2524 		rcm_log_message(RCM_ERROR,
2525 		    _("IP: get_modlist(%s): I_LIST(%s) \n"),
2526 		    name, strerror(errno));
2527 		(void) ip_plink(udp_fd, fd, &lifr);
2528 		return (-1);
2529 	}
2530 
2531 	strlist.sl_nmods = num_mods;
2532 	strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods);
2533 
2534 	if (strlist.sl_modlist == NULL) {
2535 		rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"),
2536 		    name, strerror(errno));
2537 		(void) ip_plink(udp_fd, fd, &lifr);
2538 		return (-1);
2539 	}
2540 
2541 	if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
2542 		rcm_log_message(RCM_ERROR,
2543 		    _("IP: get_modlist(%s): I_LIST error: %s\n"),
2544 		    name, strerror(errno));
2545 		(void) ip_plink(udp_fd, fd, &lifr);
2546 		return (-1);
2547 	}
2548 
2549 	for (i = 0; i < strlist.sl_nmods; i++) {
2550 		lif->li_modules[i] =
2551 		    malloc(strlen(strlist.sl_modlist[i].l_name)+1);
2552 		if (lif->li_modules[i] == NULL) {
2553 			rcm_log_message(RCM_ERROR,
2554 			    _("IP: get_modlist(%s): %s\n"),
2555 			    name, strerror(errno));
2556 			(void) ip_plink(udp_fd, fd, &lifr);
2557 			return (-1);
2558 		}
2559 		(void) strcpy(lif->li_modules[i], strlist.sl_modlist[i].l_name);
2560 	}
2561 
2562 	lif->li_modcnt = strlist.sl_nmods;
2563 	free(strlist.sl_modlist);
2564 
2565 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name);
2566 	return (ip_plink(udp_fd, fd, &lifr));
2567 }
2568 
2569 /*
2570  * ip_domux2fd() - Helper function for mod*() functions
2571  *		 Stolen from ifconfig.c
2572  */
2573 static int
2574 ip_domux2fd(int *udp_fd, int *fd, struct lifreq *lifr)
2575 {
2576 	int ip_fd;
2577 	char	*udp_dev_name;
2578 	char	*ip_dev_name;
2579 
2580 	if (lifr->lifr_flags & IFF_IPV6) {
2581 		udp_dev_name = UDP6_DEV_NAME;
2582 		ip_dev_name  = IP6_DEV_NAME;
2583 	} else {
2584 		udp_dev_name = UDP_DEV_NAME;
2585 		ip_dev_name  = IP_DEV_NAME;
2586 	}
2587 
2588 	if ((ip_fd = open(ip_dev_name, O_RDWR)) < 0) {
2589 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2590 		    ip_dev_name, strerror(errno));
2591 		return (-1);
2592 	}
2593 	if ((*udp_fd = open(udp_dev_name, O_RDWR)) < 0) {
2594 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2595 		    udp_dev_name, strerror(errno));
2596 		(void) close(ip_fd);
2597 		return (-1);
2598 	}
2599 	if (ioctl(ip_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) {
2600 		rcm_log_message(RCM_ERROR,
2601 		    _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"),
2602 		    ip_dev_name, strerror(errno));
2603 		(void) close(*udp_fd);
2604 		(void) close(ip_fd);
2605 		return (-1);
2606 	}
2607 
2608 	rcm_log_message(RCM_TRACE2,
2609 	    "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n",
2610 	    lifr->lifr_arp_muxid, lifr->lifr_ip_muxid);
2611 
2612 	if ((*fd = ioctl(*udp_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) {
2613 		rcm_log_message(RCM_ERROR,
2614 		    _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"),
2615 		    udp_dev_name, strerror(errno));
2616 		(void) close(*udp_fd);
2617 		(void) close(ip_fd);
2618 		return (-1);
2619 	}
2620 	if (ioctl(*udp_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) {
2621 		rcm_log_message(RCM_ERROR,
2622 		    _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"),
2623 		    udp_dev_name, strerror(errno));
2624 		(void) close(*udp_fd);
2625 		(void) close(ip_fd);
2626 		return (-1);
2627 	}
2628 
2629 	/* Note: udp_fd is closed in ip_plink below */
2630 	(void) close(ip_fd);
2631 	return (0);
2632 }
2633 
2634 /*
2635  * ip_plink() - Helper function for mod*() functions.
2636  *	      Stolen from ifconfig.c
2637  */
2638 static int
2639 ip_plink(int udp_fd, int fd, struct lifreq *lifr)
2640 {
2641 	int mux_id;
2642 
2643 	if ((mux_id = ioctl(udp_fd, I_PLINK, fd)) < 0) {
2644 		rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"),
2645 		    UDP_DEV_NAME, strerror(errno));
2646 		(void) close(udp_fd);
2647 		(void) close(fd);
2648 		return (-1);
2649 	}
2650 
2651 	lifr->lifr_ip_muxid = mux_id;
2652 	if (ioctl(udp_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) {
2653 		rcm_log_message(RCM_ERROR,
2654 		    _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"),
2655 		    UDP_DEV_NAME, strerror(errno));
2656 		(void) close(udp_fd);
2657 		(void) close(fd);
2658 		return (-1);
2659 	}
2660 
2661 	(void) close(udp_fd);
2662 	(void) close(fd);
2663 	return (0);
2664 }
2665 
2666 /*
2667  * ip_onlinelist()
2668  *
2669  *	Notify online to IP address consumers.
2670  */
2671 static int
2672 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2673 		rcm_info_t **depend_info)
2674 {
2675 	char **addrlist;
2676 	int ret = RCM_SUCCESS;
2677 
2678 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n");
2679 
2680 	addrlist = ip_get_addrlist(node);
2681 	if (addrlist == NULL || addrlist[0] == NULL) {
2682 		rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n");
2683 		ip_free_addrlist(addrlist);
2684 		return (ret);
2685 	}
2686 
2687 	ret = rcm_notify_online_list(hd, addrlist, 0, depend_info);
2688 
2689 	ip_free_addrlist(addrlist);
2690 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n");
2691 	return (ret);
2692 }
2693 
2694 /*
2695  * ip_offlinelist()
2696  *
2697  *	Offline IP address consumers.
2698  */
2699 static int
2700 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2701 	rcm_info_t **depend_info)
2702 {
2703 	char **addrlist;
2704 	int ret = RCM_SUCCESS;
2705 
2706 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n");
2707 
2708 	addrlist = ip_get_addrlist(node);
2709 	if (addrlist == NULL || addrlist[0] == NULL) {
2710 		rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n");
2711 		ip_free_addrlist(addrlist);
2712 		return (RCM_SUCCESS);
2713 	}
2714 
2715 	if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info))
2716 	    != RCM_SUCCESS) {
2717 		if (ret == RCM_FAILURE)
2718 			(void) rcm_notify_online_list(hd, addrlist, 0, NULL);
2719 
2720 		ret = RCM_FAILURE;
2721 	}
2722 
2723 	ip_free_addrlist(addrlist);
2724 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n");
2725 	return (ret);
2726 }
2727 
2728 /*
2729  * ip_get_addrlist() -	Compile list of IP addresses hosted on this NIC (node)
2730  *			This routine malloc() required memeory for the list
2731  *			Returns list on success, NULL if failed
2732  *			Call with cache_lock held.
2733  */
2734 static char **
2735 ip_get_addrlist(ip_cache_t *node)
2736 {
2737 	ip_lif_t *lif;
2738 	char **addrlist = NULL;
2739 	int numifs;
2740 	char addrstr[INET6_ADDRSTRLEN];
2741 	void *addr;
2742 	int af;
2743 	int i;
2744 
2745 	rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n",
2746 	    node->ip_resource);
2747 
2748 	numifs = 0;
2749 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
2750 		numifs++;
2751 	}
2752 
2753 	/*
2754 	 * Allocate space for resource names list; add 1 and use calloc()
2755 	 * so that the list is NULL-terminated.
2756 	 */
2757 	if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) {
2758 		rcm_log_message(RCM_ERROR,
2759 		    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2760 		    node->ip_resource, strerror(errno));
2761 		return (NULL);
2762 	}
2763 
2764 	for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL;
2765 	    lif = lif->li_next, i++) {
2766 
2767 		af = lif->li_addr.family;
2768 		if (af == AF_INET6) {
2769 			addr = &lif->li_addr.ip6.sin6_addr;
2770 		} else if (af == AF_INET) {
2771 			addr = &lif->li_addr.ip4.sin_addr;
2772 		} else {
2773 			rcm_log_message(RCM_DEBUG,
2774 			    "IP: unknown addr family %d, assuming AF_INET\n",
2775 			    af);
2776 			af = AF_INET;
2777 			addr = &lif->li_addr.ip4.sin_addr;
2778 		}
2779 		if (inet_ntop(af, addr, addrstr, INET6_ADDRSTRLEN) == NULL) {
2780 			rcm_log_message(RCM_ERROR,
2781 			    _("IP: inet_ntop: %s\n"), strerror(errno));
2782 			ip_free_addrlist(addrlist);
2783 			return (NULL);
2784 		}
2785 
2786 		if ((addrlist[i] = malloc(strlen(addrstr) + RCM_SIZE_SUNW_IP))
2787 		    == NULL) {
2788 			rcm_log_message(RCM_ERROR,
2789 			    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2790 			    node->ip_resource, strerror(errno));
2791 			ip_free_addrlist(addrlist);
2792 			return (NULL);
2793 		}
2794 		(void) strcpy(addrlist[i], RCM_STR_SUNW_IP);	/* SUNW_ip/ */
2795 		(void) strcat(addrlist[i], addrstr);	/* SUNW_ip/<address> */
2796 
2797 		rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]);
2798 	}
2799 
2800 	rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n",
2801 	    node->ip_resource);
2802 
2803 	return (addrlist);
2804 }
2805 
2806 static void
2807 ip_free_addrlist(char **addrlist)
2808 {
2809 	int i;
2810 
2811 	if (addrlist == NULL)
2812 		return;
2813 
2814 	for (i = 0; addrlist[i] != NULL; i++)
2815 		free(addrlist[i]);
2816 	free(addrlist);
2817 }
2818 
2819 /*
2820  * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
2821  */
2822 
2823 static void
2824 ip_consumer_notify(rcm_handle_t *hd, char *ifinst, char **errorp, uint_t flags,
2825 	rcm_info_t **depend_info)
2826 {
2827 	char ifname[LIFNAMSIZ + 1];
2828 	char cached_name[RCM_NET_RESOURCE_MAX];
2829 	ip_cache_t *node;
2830 	char *cp;
2831 
2832 	rcm_log_message(RCM_TRACE1, "IP: ip_consumer_notify(%s)\n", ifinst);
2833 
2834 	if (ifinst == NULL)
2835 		return;
2836 
2837 	(void) memcpy(&ifname, ifinst, sizeof (ifname));
2838 	ifname[sizeof (ifname) - 1] = '\0';
2839 
2840 	/* remove LIF component */
2841 	cp = strchr(ifname, ':');
2842 	if (cp) {
2843 		*cp = 0;
2844 	}
2845 
2846 	/* Check for the interface in the cache */
2847 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%s",
2848 	    RCM_NET_PREFIX, ifname);
2849 
2850 	(void) mutex_lock(&cache_lock);
2851 	if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) {
2852 		rcm_log_message(RCM_TRACE1, "IP: Skipping interface(%s) \n",
2853 		    ifname);
2854 		(void) mutex_unlock(&cache_lock);
2855 		return;
2856 	}
2857 	/*
2858 	 * Inform anonymous consumers about IP addresses being
2859 	 * onlined
2860 	 */
2861 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
2862 
2863 	(void) mutex_unlock(&cache_lock);
2864 
2865 	rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n");
2866 	return;
2867 
2868 }
2869 /*
2870  * process_nvlist() - Determine network interfaces on a new attach by
2871  *			processing the nvlist
2872  */
2873 /*ARGSUSED*/
2874 static int
2875 process_nvlist(nvlist_t *nvl)
2876 {
2877 	nvpair_t	*nvp = NULL;
2878 	char *driver_name;
2879 	char *devfs_path;
2880 	int32_t instance;
2881 	char *minor_byte_array;	/* packed nvlist of minor_data */
2882 	uint_t nminor;			/* # of minor nodes */
2883 	struct devfs_minor_data *mdata;
2884 	nvlist_t *mnvl;
2885 	nvpair_t *mnvp = NULL;
2886 
2887 	rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n");
2888 
2889 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
2890 		/* Get driver name */
2891 		if (STREQ(nvpair_name(nvp), RCM_NV_DRIVER_NAME)) {
2892 			if (nvpair_value_string(nvp, &driver_name) != 0) {
2893 				rcm_log_message(RCM_WARNING,
2894 				    _("IP: cannot get driver name\n"));
2895 				return (-1);
2896 			}
2897 		}
2898 		/* Get instance */
2899 		if (STREQ(nvpair_name(nvp), RCM_NV_INSTANCE)) {
2900 			if (nvpair_value_int32(nvp, &instance) != 0) {
2901 				rcm_log_message(RCM_WARNING,
2902 				    _("IP: cannot get device instance\n"));
2903 				return (-1);
2904 			}
2905 		}
2906 		/* Get devfs_path */
2907 		if (STREQ(nvpair_name(nvp), RCM_NV_DEVFS_PATH)) {
2908 			if (nvpair_value_string(nvp, &devfs_path) != 0) {
2909 				rcm_log_message(RCM_WARNING,
2910 				    _("IP: cannot get device path\n"));
2911 				return (-1);
2912 			}
2913 		}
2914 		/* Get minor data */
2915 		if (STREQ(nvpair_name(nvp), RCM_NV_MINOR_DATA)) {
2916 			if (nvpair_value_byte_array(nvp,
2917 			    (uchar_t **)&minor_byte_array, &nminor) != 0) {
2918 				rcm_log_message(RCM_WARNING,
2919 				    _("IP: cannot get device minor data\n"));
2920 				return (-1);
2921 			}
2922 			if (nvlist_unpack(minor_byte_array,
2923 			    nminor, &mnvl, 0) != 0) {
2924 				rcm_log_message(RCM_WARNING,
2925 				    _("IP: cannot get minor node data\n"));
2926 				return (-1);
2927 			}
2928 			mdata = (struct devfs_minor_data *)calloc(1,
2929 			    sizeof (struct devfs_minor_data));
2930 			if (mdata == NULL) {
2931 				rcm_log_message(RCM_WARNING,
2932 				    _("IP: calloc error(%s)\n"),
2933 				    strerror(errno));
2934 				nvlist_free(mnvl);
2935 				return (-1);
2936 			}
2937 			/* Enumerate minor node data */
2938 			while ((mnvp = nvlist_next_nvpair(mnvl, mnvp)) !=
2939 			    NULL) {
2940 				/* Get minor type */
2941 				if (STREQ(nvpair_name(mnvp),
2942 				    RCM_NV_MINOR_TYPE)) {
2943 					if (nvpair_value_int32(mnvp,
2944 					    &mdata->minor_type) != 0) {
2945 						rcm_log_message(RCM_WARNING,
2946 						    _("IP: cannot get minor "
2947 						    "type \n"));
2948 						nvlist_free(mnvl);
2949 						return (-1);
2950 					}
2951 				}
2952 				/* Get minor name */
2953 				if (STREQ(nvpair_name(mnvp),
2954 				    RCM_NV_MINOR_NAME)) {
2955 					if (nvpair_value_string(mnvp,
2956 					    &mdata->minor_name) != 0) {
2957 						rcm_log_message(RCM_WARNING,
2958 						    _("IP: cannot get minor "
2959 						    "name \n"));
2960 						nvlist_free(mnvl);
2961 						return (-1);
2962 					}
2963 				}
2964 				/* Get minor node type */
2965 				if (STREQ(nvpair_name(mnvp),
2966 				    RCM_NV_MINOR_NODE_TYPE)) {
2967 					if (nvpair_value_string(mnvp,
2968 					    &mdata->minor_node_type) != 0) {
2969 						rcm_log_message(RCM_WARNING,
2970 						    _("IP: cannot get minor "
2971 						    "node type \n"));
2972 						nvlist_free(mnvl);
2973 						return (-1);
2974 					}
2975 				}
2976 			}
2977 			(void) process_minor(devfs_path, driver_name, instance,
2978 			    mdata);
2979 			nvlist_free(mnvl);
2980 		}
2981 	}
2982 
2983 	rcm_log_message(RCM_TRACE1, "IP: process_nvlist success\n");
2984 	return (0);
2985 }
2986 
2987 static void
2988 process_minor(char *devfs_path, char *name, int instance,
2989     struct devfs_minor_data *mdata)
2990 {
2991 	struct net_interface *nip;
2992 	struct ni_list *nilp;
2993 	struct ni_list *p;
2994 	struct ni_list **pp;
2995 	char *cname;
2996 	size_t cnamelen;
2997 
2998 	rcm_log_message(RCM_TRACE1, "IP: process_minor\n");
2999 
3000 	if ((mdata->minor_node_type != NULL) &&
3001 	    !STREQ(mdata->minor_node_type, PROP_NV_DDI_NETWORK)) {
3002 		/* Process network devices only */
3003 		return;
3004 	}
3005 
3006 	rcm_log_message(RCM_TRACE1, "IP: Examining %s (%s)\n",
3007 	    devfs_path, mdata->minor_name);
3008 
3009 	/* Sanity check, instances > 999 are illegal */
3010 	if (instance > 999) {
3011 		errno = EINVAL;
3012 		rcm_log_message(RCM_ERROR, _("IP: invalid instance %d(%s)\n"),
3013 		    instance, strerror(errno));
3014 		return;
3015 	}
3016 
3017 	/* Now, let's add the node to the interface list */
3018 	if ((nip = malloc(sizeof (struct net_interface))) == NULL) {
3019 		rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"),
3020 		    strerror(errno));
3021 		return;
3022 	}
3023 	(void) memset(nip, 0, sizeof (struct net_interface));
3024 
3025 	cnamelen = strlen(name) + 1;
3026 	/* Set NIC type */
3027 	if ((nip->type = (char *)malloc(cnamelen)) == NULL) {
3028 		free(nip);
3029 		rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"),
3030 		    strerror(errno));
3031 		return;
3032 	}
3033 	(void) memcpy(nip->type, name, cnamelen);
3034 
3035 	cnamelen += 3;
3036 	if ((cname = (char *)malloc(cnamelen)) == NULL) {
3037 		free(nip->type);
3038 		free(nip);
3039 		rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"),
3040 		    strerror(errno));
3041 		return;
3042 	}
3043 	(void) snprintf(cname, cnamelen, "%s%d", name, instance);
3044 
3045 	rcm_log_message(RCM_TRACE1, "IP: Found SUNW_network/%s%d\n", name,
3046 	    instance);
3047 
3048 	/* Set NIC name */
3049 	if ((nip->name = strdup(cname)) == NULL) {
3050 		free(nip->type);
3051 		free(nip);
3052 		free(cname);
3053 		rcm_log_message(RCM_ERROR, _("IP: strdup failure(%s)\n"),
3054 		    strerror(errno));
3055 		return;
3056 	}
3057 	free(cname);
3058 
3059 	/* Add new interface to the list */
3060 	(void) mutex_lock(&nil_lock);
3061 	for (pp = &nil_head; (p = *pp) != NULL; pp = &(p->next)) {
3062 		cname = p->nifp->name;
3063 		if (strcmp(cname, nip->name) == 0)
3064 			break;
3065 	}
3066 
3067 	if (p != NULL) {
3068 		(void) mutex_unlock(&nil_lock);
3069 		free(nip->name);
3070 		free(nip->type);
3071 		free(nip);
3072 		rcm_log_message(RCM_TRACE1, "IP: secondary node - ignoring\n");
3073 		return;
3074 	}
3075 
3076 	if ((nilp = malloc(sizeof (struct ni_list))) == NULL) {
3077 		(void) mutex_unlock(&nil_lock);
3078 		free(nip->name);
3079 		free(nip->type);
3080 		free(nip);
3081 		rcm_log_message(RCM_ERROR, _("IP: malloc failure(%s)\n"),
3082 		    strerror(errno));
3083 		return;
3084 	}
3085 
3086 	nilp->nifp = nip;
3087 	nilp->next = NULL;
3088 	*pp = nilp;
3089 
3090 	num_ni++;	/* Increment interface count */
3091 
3092 	(void) mutex_unlock(&nil_lock);
3093 	rcm_log_message(RCM_TRACE1, "IP: added new node\n");
3094 }
3095 
3096 /*
3097  * if_configure() - Configure a physical interface after attach
3098  */
3099 static int
3100 if_configure(char *ifinst)
3101 {
3102 	char cfgfile[MAXPATHLEN];
3103 	char ifname[LIFNAMSIZ + 1];
3104 	char cached_name[RCM_NET_RESOURCE_MAX];
3105 	struct stat statbuf;
3106 	ip_cache_t *node;
3107 	char *cp;
3108 	int af = 0;
3109 	int ipmp = 0;
3110 
3111 	if (ifinst == NULL)
3112 		return (0);
3113 
3114 	rcm_log_message(RCM_TRACE1, "IP: if_configure(%s)\n", ifinst);
3115 
3116 	/*
3117 	 * Check if the interface is already configured
3118 	 */
3119 
3120 	(void) memcpy(&ifname, ifinst, sizeof (ifname));
3121 	ifname[sizeof (ifname) - 1] = '\0';
3122 
3123 	/* remove LIF component */
3124 	cp = strchr(ifname, ':');
3125 	if (cp) {
3126 		*cp = 0;
3127 	}
3128 
3129 	/* Check for the interface in the cache */
3130 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%s",
3131 	    RCM_NET_PREFIX, ifname);
3132 
3133 	/* Check if the interface is new or was previously offlined */
3134 	(void) mutex_lock(&cache_lock);
3135 	if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) &&
3136 	    (!(node->ip_cachestate & CACHE_IF_OFFLINED))) {
3137 		rcm_log_message(RCM_TRACE1,
3138 		    "IP: Skipping configured interface(%s) \n", ifname);
3139 		(void) mutex_unlock(&cache_lock);
3140 		return (0);
3141 	}
3142 	(void) mutex_unlock(&cache_lock);
3143 
3144 	/* Scan IPv4 configuration first */
3145 	(void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4, ifinst);
3146 	cfgfile[MAXPATHLEN - 1] = '\0';
3147 
3148 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
3149 	if (stat(cfgfile, &statbuf) == 0) {
3150 		af |= CONFIG_AF_INET;
3151 		if (isgrouped(cfgfile)) {
3152 			ipmp++;
3153 		}
3154 	}
3155 
3156 	/* Scan IPv6 configuration details */
3157 	(void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV6, ifinst);
3158 	cfgfile[MAXPATHLEN - 1] = '\0';
3159 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
3160 	if (stat(cfgfile, &statbuf) == 0) {
3161 		af |= CONFIG_AF_INET6;
3162 		if ((ipmp == 0) && isgrouped(cfgfile)) {
3163 			ipmp++;
3164 		}
3165 	}
3166 
3167 	if (af & CONFIG_AF_INET) {
3168 		if (if_ipmp_config(ifinst, CONFIG_AF_INET, ipmp) == -1) {
3169 			rcm_log_message(RCM_ERROR,
3170 			    _("IP: IPv4 Post-attach failed (%s)\n"), ifinst);
3171 			return (-1);
3172 		}
3173 	}
3174 
3175 	if (af & CONFIG_AF_INET6) {
3176 		if (if_ipmp_config(ifinst, CONFIG_AF_INET6, ipmp) == -1) {
3177 			rcm_log_message(RCM_ERROR,
3178 			    _("IP: IPv6 Post-attach failed(%s)\n"), ifinst);
3179 			return (-1);
3180 		}
3181 	}
3182 
3183 	rcm_log_message(RCM_TRACE1, "IP: if_configure(%s) success\n", ifinst);
3184 
3185 	return (0);
3186 
3187 }
3188 
3189 /*
3190  * isgrouped() - Scans the given config file to see if this is a grouped
3191  *	       interface
3192  *	       Returns non-zero if true; 0 if false
3193  */
3194 static int
3195 isgrouped(char *cfgfile)
3196 {
3197 	FILE *fp;
3198 	struct stat statb;
3199 	char *buf = NULL;
3200 	char *tokens[MAXARGS];		/* token pointers */
3201 	char tspace[MAXLINE];		/* token space */
3202 	int ntok;
3203 	int group = 0;
3204 
3205 	if (cfgfile == NULL)
3206 		return (0);
3207 
3208 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile);
3209 
3210 	if (stat(cfgfile, &statb) != 0) {
3211 		rcm_log_message(RCM_TRACE1,
3212 		    _("IP: No config file(%s)\n"), cfgfile);
3213 		return (0);
3214 	}
3215 
3216 	/*
3217 	 * We also ignore single-byte config files because the file should
3218 	 * always be newline-terminated, so we know there's nothing of
3219 	 * interest.  Further, a single-byte file would cause the fgets() loop
3220 	 * below to spin forever.
3221 	 */
3222 	if (statb.st_size <= 1) {
3223 		rcm_log_message(RCM_TRACE1,
3224 		    _("IP: Empty config file(%s)\n"), cfgfile);
3225 		return (0);
3226 	}
3227 
3228 	if ((fp = fopen(cfgfile, "r")) == NULL) {
3229 		rcm_log_message(RCM_ERROR,
3230 		    _("IP: Cannot open configuration file(%s): %s\n"), cfgfile,
3231 		    strerror(errno));
3232 		return (0);
3233 	}
3234 
3235 	if ((buf = calloc(1, statb.st_size)) == NULL) {
3236 		rcm_log_message(RCM_ERROR,
3237 		    _("IP: calloc failure(%s): %s\n"), cfgfile,
3238 		    strerror(errno));
3239 		(void) fclose(fp);
3240 		return (0);
3241 	}
3242 
3243 	while (fgets(buf, statb.st_size, fp) != NULL) {
3244 		if (*buf == '\0')
3245 			continue;
3246 
3247 		tokenize(buf, tokens, tspace, &ntok);
3248 		while (ntok) {
3249 			if (STREQ("group", tokens[ntok - 1])) {
3250 				if (tokens[ntok] != NULL) {
3251 					group++;
3252 				}
3253 			}
3254 			ntok--;
3255 		}
3256 	}
3257 
3258 	free(buf);
3259 
3260 	(void) fclose(fp);
3261 
3262 	if (group <= 0) {
3263 		rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s) non-grouped\n",
3264 		    cfgfile);
3265 		return (0);
3266 	} else {
3267 		rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s) grouped\n",
3268 		    cfgfile);
3269 		return (1);
3270 	}
3271 }
3272 
3273 
3274 /*
3275  * if_ipmp_config() - Configure an interface instance as specified by the
3276  *		    address family af and if it is grouped (ipmp).
3277  */
3278 static int
3279 if_ipmp_config(char *ifinst, int af, int ipmp)
3280 {
3281 	char cfgfile[MAXPATHLEN];	/* configuration file */
3282 	FILE *fp;
3283 	struct stat statb;
3284 	char *buf;
3285 	char *tokens[MAXARGS];		/* list of config attributes */
3286 	char tspace[MAXLINE];		/* token space */
3287 	char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
3288 	char grpcmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
3289 	char fstr[8];		/* address family string inet or inet6 */
3290 	int nofailover = 0;
3291 	int newattach = 0;
3292 	int cmdvalid = 0;
3293 	int ntok;
3294 	int n;
3295 	int stdif = 0;
3296 
3297 	if (ifinst == NULL)
3298 		return (0);
3299 
3300 	rcm_log_message(RCM_TRACE1, "IP: if_ipmp_config(%s) ipmp = %d\n",
3301 	    ifinst, ipmp);
3302 
3303 	if (af & CONFIG_AF_INET) {
3304 		(void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV4,
3305 		    ifinst);
3306 		(void) strcpy(fstr, "inet");
3307 	} else if (af & CONFIG_AF_INET6) {
3308 		(void) snprintf(cfgfile, MAXPATHLEN, "%s%s", CFGFILE_FMT_IPV6,
3309 		    ifinst);
3310 		(void) strcpy(fstr, "inet6");
3311 	} else {
3312 		return (0);		/* nothing to do */
3313 	}
3314 
3315 	cfgfile[MAXPATHLEN - 1] = '\0';
3316 	grpcmd[0] = '\0';
3317 
3318 	if (stat(cfgfile, &statb) != 0) {
3319 		rcm_log_message(RCM_TRACE1,
3320 		    _("IP: No config file(%s)\n"), ifinst);
3321 		return (0);
3322 	}
3323 
3324 	/* Config file exists, plumb in the physical interface */
3325 	if (af & CONFIG_AF_INET6) {
3326 		if (if_getcount(AF_INET6) == 0) {
3327 			/*
3328 			 * Configure software loopback driver if this is the
3329 			 * first IPv6 interface plumbed
3330 			 */
3331 			newattach++;
3332 			(void) snprintf(syscmd, sizeof (syscmd),
3333 			    "%s lo0 %s plumb ::1 up", USR_SBIN_IFCONFIG, fstr);
3334 			if (rcm_exec_cmd(syscmd) != 0) {
3335 				rcm_log_message(RCM_ERROR,
3336 				    _("IP: Cannot plumb (%s) %s\n"),
3337 				    ifinst, strerror(errno));
3338 				return (-1);
3339 			}
3340 		}
3341 		(void) snprintf(syscmd, sizeof (syscmd), "%s %s %s plumb up",
3342 		    USR_SBIN_IFCONFIG, ifinst, fstr);
3343 	} else {
3344 		(void) snprintf(syscmd, sizeof (syscmd), "%s %s %s plumb ",
3345 		    USR_SBIN_IFCONFIG, ifinst, fstr);
3346 		if (if_getcount(AF_INET) == 0) {
3347 			newattach++;
3348 		}
3349 	}
3350 	rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd);
3351 
3352 	if (rcm_exec_cmd(syscmd) != 0) {
3353 		rcm_log_message(RCM_ERROR,
3354 		    _("IP: Cannot plumb (%s) %s\n"), ifinst, strerror(errno));
3355 		return (-1);
3356 	}
3357 
3358 	/* Check if config file is empty, if so, nothing else to do */
3359 	if (statb.st_size == 0) {
3360 		rcm_log_message(RCM_TRACE1,
3361 		    _("IP: Zero size config file(%s)\n"), ifinst);
3362 		return (0);
3363 	}
3364 
3365 	if ((fp = fopen(cfgfile, "r")) == NULL) {
3366 		rcm_log_message(RCM_ERROR,
3367 		    _("IP: Open error(%s): %s\n"), cfgfile, strerror(errno));
3368 		return (-1);
3369 	}
3370 
3371 	if ((buf = calloc(1, statb.st_size)) == NULL) {
3372 		rcm_log_message(RCM_ERROR,
3373 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
3374 		(void) fclose(fp);
3375 		return (-1);
3376 	}
3377 
3378 	/* a single line with one token implies a classical if */
3379 	if (fgets(buf, statb.st_size, fp) != NULL) {
3380 		tokenize(buf, tokens, tspace, &ntok);
3381 		if (ntok == 1) {
3382 			rcm_log_message(RCM_TRACE1, "IP: Standard interface\n");
3383 			stdif++;
3384 		}
3385 	}
3386 	if (fseek(fp, 0L, SEEK_SET) == -1) {
3387 		rcm_log_message(RCM_ERROR, _("IP: fseek: %s\n"),
3388 		    strerror(errno));
3389 		return (-1);
3390 	}
3391 
3392 	/*
3393 	 * Process the config command
3394 	 * This loop also handles multiple logical interfaces that may
3395 	 * be configured on a single line
3396 	 */
3397 	while (fgets(buf, statb.st_size, fp) != NULL) {
3398 		nofailover = 0;
3399 		cmdvalid = 0;
3400 
3401 		if (*buf == '\0')
3402 			continue;
3403 
3404 		tokenize(buf, tokens, tspace, &ntok);
3405 		if (ntok <= 0)
3406 			continue;
3407 
3408 		/* Reset the config command */
3409 		(void) snprintf(syscmd, sizeof (syscmd), "%s %s %s ",
3410 		    USR_SBIN_IFCONFIG, ifinst, fstr);
3411 
3412 		/* No parsing if this is first interface of its kind */
3413 		if (newattach) {
3414 			(void) strcat(syscmd, buf);
3415 			/* Classic if */
3416 			if ((af & CONFIG_AF_INET) && (stdif == 1)) {
3417 				(void) strcat(syscmd, CFG_CMDS_STD);
3418 			}
3419 			rcm_log_message(RCM_TRACE1, "IP: New: %s\n", syscmd);
3420 			if (rcm_exec_cmd(syscmd) != 0) {
3421 				rcm_log_message(RCM_ERROR,
3422 				    _("IP: Error: %s (%s): %s\n"),
3423 				    syscmd, ifinst, strerror(errno));
3424 			}
3425 			continue;
3426 		}
3427 
3428 		/* Parse the tokens to determine nature of the interface */
3429 		for (n = 0; n < ntok; n++) {
3430 			/* Handle pathological failover cases */
3431 			if (STREQ("-failover", tokens[n]))
3432 				nofailover++;
3433 			if (STREQ("failover", tokens[n]))
3434 				nofailover--;
3435 
3436 			/* group attribute requires special processing */
3437 			if (STREQ("group", tokens[n])) {
3438 				if (tokens[n + 1] != NULL) {
3439 					(void) snprintf(grpcmd, sizeof (grpcmd),
3440 					    "%s %s %s %s %s", USR_SBIN_IFCONFIG,
3441 					    ifinst, fstr,
3442 					    tokens[n], tokens[n + 1]);
3443 					n++;		/* skip next token */
3444 					continue;
3445 				}
3446 			}
3447 
3448 			/* Execute buffered command ? */
3449 			if (STREQ("set", tokens[n]) ||
3450 			    STREQ("addif", tokens[n]) ||
3451 			    STREQ("removeif", tokens[n]) ||
3452 			    (n == (ntok -1))) {
3453 
3454 				/* config command complete ? */
3455 				if (n == (ntok -1)) {
3456 					ADDSPACE(syscmd);
3457 					(void) strcat(syscmd, tokens[n]);
3458 					cmdvalid++;
3459 				}
3460 
3461 				if (!cmdvalid) {
3462 					ADDSPACE(syscmd);
3463 					(void) strcat(syscmd, tokens[n]);
3464 					cmdvalid++;
3465 					continue;
3466 				}
3467 				/* Classic if ? */
3468 				if ((af & CONFIG_AF_INET) && (stdif == 1)) {
3469 					(void) strcat(syscmd, CFG_CMDS_STD);
3470 				}
3471 
3472 				if (nofailover > 0) {
3473 					rcm_log_message(RCM_TRACE1,
3474 					    "IP: Interim exec: %s\n", syscmd);
3475 					if (rcm_exec_cmd(syscmd) != 0) {
3476 						rcm_log_message(RCM_ERROR,
3477 						    _("IP: %s fail(%s): %s\n"),
3478 						    syscmd, ifinst,
3479 						    strerror(errno));
3480 					}
3481 				} else {
3482 					/* Have mpathd configure the address */
3483 					if (if_mpathd_configure(syscmd, ifinst,
3484 					    af, ipmp) != 0) {
3485 						rcm_log_message(RCM_ERROR,
3486 						    _("IP: %s fail(%s): %s\n"),
3487 						    syscmd, ifinst,
3488 						    strerror(errno));
3489 					}
3490 				}
3491 
3492 				/* Reset config command */
3493 				(void) snprintf(syscmd, sizeof (syscmd),
3494 				    "%s %s %s ", USR_SBIN_IFCONFIG, ifinst,
3495 				    fstr);
3496 				nofailover = 0;
3497 				cmdvalid = 0;
3498 			}
3499 			/*
3500 			 * Note: No explicit command validation is required
3501 			 *	since ifconfig to does it for us
3502 			 */
3503 			ADDSPACE(syscmd);
3504 			(void) strcat(syscmd, tokens[n]);
3505 			cmdvalid++;
3506 		}
3507 	}
3508 
3509 	free(buf);
3510 	(void) fclose(fp);
3511 
3512 	/*
3513 	 * The group name needs to be set after all the test/nofailover
3514 	 * addresses have been configured. Otherwise, if IPMP detects that the
3515 	 * interface is failed, the addresses will be moved to a working
3516 	 * interface before the '-failover' flag can be set.
3517 	 */
3518 	if (grpcmd[0] != '\0') {
3519 		rcm_log_message(RCM_TRACE1, "IP: set group name: %s\n", grpcmd);
3520 		if (rcm_exec_cmd(grpcmd) != 0) {
3521 			rcm_log_message(RCM_ERROR, _("IP: %s fail(%s): %s\n"),
3522 			    grpcmd, ifinst, strerror(errno));
3523 		}
3524 	}
3525 
3526 	rcm_log_message(RCM_TRACE1, "IP: if_ipmp_config(%s) success\n", ifinst);
3527 
3528 	return (0);
3529 }
3530 
3531 /*
3532  * if_mpathd_configure() - Determine configuration disposition of the interface
3533  */
3534 static int
3535 if_mpathd_configure(char *syscmd, char *ifinst, int af, int ipmp)
3536 {
3537 	char *tokens[MAXARGS];
3538 	char tspace[MAXLINE];
3539 	int ntok;
3540 	char *addr;
3541 	char *from_lifname;
3542 	mpathd_cmd_t mpdcmd;
3543 	int n;
3544 
3545 	rcm_log_message(RCM_TRACE1, "IP: if_mpathd_configure(%s): %s\n",
3546 	    ifinst, syscmd);
3547 
3548 	tokenize(syscmd, tokens, tspace, &ntok);
3549 	if (ntok <= 0)
3550 		return (0);
3551 
3552 	addr = tokens[3];	/* by default, third token is valid address */
3553 	for (n = 0; n < ntok; n++) {
3554 		if (STREQ("set", tokens[n]) ||
3555 		    STREQ("addif", tokens[n])) {
3556 			addr = tokens[n+1];
3557 			if (addr == NULL) {	/* invalid format */
3558 				return (-1);
3559 			} else
3560 				break;
3561 		}
3562 	}
3563 
3564 	/* Check std. commands or no failed over address */
3565 	if (STREQ("removeif", addr) || STREQ("group", addr) ||
3566 	    ((from_lifname = get_mpathd_dest(addr, af)) == NULL)) {
3567 		rcm_log_message(RCM_TRACE1,
3568 		    "IP: No failed-over host, exec %s\n", syscmd);
3569 		if (rcm_exec_cmd(syscmd) != 0) {
3570 			rcm_log_message(RCM_ERROR,
3571 			    _("IP: %s failed(%s): %s\n"),
3572 			    syscmd, ifinst, strerror(errno));
3573 			return (-1);
3574 		}
3575 		return (0);
3576 	}
3577 
3578 	/* Check for non-IPMP failover scenarios */
3579 	if ((ipmp <= 0) && (from_lifname != NULL)) {
3580 		/* Address already hosted on another NIC, return */
3581 		rcm_log_message(RCM_TRACE1,
3582 		    "IP: Non-IPMP failed-over host(%s): %s\n",
3583 		    ifinst, addr);
3584 		return (0);
3585 	}
3586 
3587 	/*
3588 	 * Valid failed-over host; have mpathd set the original index
3589 	 */
3590 	mpdcmd.cmd_command = MI_SETOINDEX;
3591 	(void) strcpy(mpdcmd.from_lifname, from_lifname);
3592 	(void) strcpy(mpdcmd.to_pifname, ifinst);
3593 	if (af & CONFIG_AF_INET6) {
3594 		mpdcmd.addr_family = AF_INET6;
3595 	} else {
3596 		mpdcmd.addr_family = AF_INET;
3597 	}
3598 
3599 	/* Send command to in.mpathd(1M) */
3600 	rcm_log_message(RCM_TRACE1,
3601 	    "IP: Attempting setoindex from (%s) to (%s) ....\n",
3602 	    from_lifname, ifinst);
3603 
3604 	if (mpathd_send_cmd(&mpdcmd) < 0) {
3605 		rcm_log_message(RCM_TRACE1,
3606 		    _("IP: mpathd set original index unsuccessful: %s\n"),
3607 		    strerror(errno));
3608 		return (-1);
3609 	}
3610 
3611 	rcm_log_message(RCM_TRACE1,
3612 	    "IP: setoindex success (%s) to (%s)\n",
3613 	    from_lifname, ifinst);
3614 
3615 	return (0);
3616 }
3617 
3618 /*
3619  * get_mpathd_addr() - Return current destination for lif; caller is
3620  *		     responsible to free memory allocated for address
3621  */
3622 static char *
3623 get_mpathd_dest(char *addr, int family)
3624 {
3625 	int sock;
3626 	char *buf;
3627 	struct lifnum lifn;
3628 	struct lifconf lifc;
3629 	struct lifreq *lifrp;
3630 	sa_family_t af = AF_INET;	/* IPv4 by default */
3631 	int i;
3632 	struct lifreq lifreq;
3633 	struct sockaddr_in *sin;
3634 	struct sockaddr_in6 *sin6;
3635 	struct hostent *hp;
3636 	char *ifname = NULL;
3637 	char *prefix = NULL;
3638 	char addrstr[INET6_ADDRSTRLEN];
3639 	char ifaddr[INET6_ADDRSTRLEN];
3640 	int err;
3641 
3642 	if (addr == NULL) {
3643 		return (NULL);
3644 	}
3645 
3646 	rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s)\n", addr);
3647 
3648 	if (family & CONFIG_AF_INET6) {
3649 		af = AF_INET6;
3650 	} else {
3651 		af = AF_INET;
3652 	}
3653 
3654 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
3655 		rcm_log_message(RCM_ERROR,
3656 		    _("IP: failure opening %s socket: %s\n"),
3657 		    af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
3658 		return (NULL);
3659 	}
3660 
3661 	lifn.lifn_family = af;
3662 	lifn.lifn_flags = 0;
3663 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
3664 		rcm_log_message(RCM_ERROR,
3665 		    _("IP: SIOCLGIFNUM failed: %s\n"),
3666 		    strerror(errno));
3667 		(void) close(sock);
3668 		return (NULL);
3669 	}
3670 
3671 	if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) {
3672 		rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
3673 		    strerror(errno));
3674 		(void) close(sock);
3675 		return (NULL);
3676 	}
3677 
3678 	lifc.lifc_family = af;
3679 	lifc.lifc_flags = 0;
3680 	lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count;
3681 	lifc.lifc_buf = buf;
3682 
3683 	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
3684 		rcm_log_message(RCM_ERROR,
3685 		    _("IP: SIOCGLIFCONF failed: %s\n"),
3686 		    strerror(errno));
3687 		free(buf);
3688 		(void) close(sock);
3689 		return (NULL);
3690 	}
3691 
3692 	/* Filter out prefix address from netmask */
3693 	(void) strcpy(ifaddr, addr);
3694 	if ((prefix = strchr(ifaddr, '/')) != NULL) {
3695 		*prefix = '\0';	/* We care about the address part only */
3696 	}
3697 
3698 	/* Check for aliases */
3699 	hp = getipnodebyname(ifaddr, af, AI_DEFAULT, &err);
3700 	if (hp) {
3701 		if (inet_ntop(af, (void *)hp->h_addr_list[0],
3702 		    ifaddr, sizeof (ifaddr)) == NULL) {
3703 			/* Restore original address and use it */
3704 			(void) strcpy(ifaddr, addr);
3705 			if ((prefix = strchr(ifaddr, '/')) != NULL) {
3706 				*prefix = '\0';
3707 			}
3708 		}
3709 		freehostent(hp);
3710 	}
3711 	rcm_log_message(RCM_TRACE2, "IP: ifaddr(%s) = %s\n",
3712 		    addr, ifaddr);
3713 
3714 	/* now search the interfaces */
3715 	lifrp = lifc.lifc_req;
3716 	for (i = 0; i < lifn.lifn_count; i++, lifrp++) {
3717 		(void) strcpy(lifreq.lifr_name, lifrp->lifr_name);
3718 		/* Get the interface address for this interface */
3719 		if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) {
3720 			rcm_log_message(RCM_ERROR,
3721 			    _("IP: SIOCGLIFADDR: %s\n"), strerror(errno));
3722 			free(buf);
3723 			(void) close(sock);
3724 			return (NULL);
3725 		}
3726 
3727 		if (af == AF_INET6) {
3728 			sin6 = (struct sockaddr_in6 *)&lifreq.lifr_addr;
3729 			if (inet_ntop(AF_INET6, (void *)&sin6->sin6_addr,
3730 			    addrstr, sizeof (addrstr)) == NULL) {
3731 				continue;
3732 			}
3733 		} else {
3734 			sin = (struct sockaddr_in *)&lifreq.lifr_addr;
3735 			if (inet_ntop(AF_INET, (void *)&sin->sin_addr,
3736 			    addrstr, sizeof (addrstr)) == NULL) {
3737 				continue;
3738 			}
3739 		}
3740 
3741 		if (STREQ(addrstr, ifaddr)) {
3742 			/* Allocate memory to hold interface name */
3743 			if ((ifname = (char *)malloc(LIFNAMSIZ)) == NULL) {
3744 				rcm_log_message(RCM_ERROR,
3745 				    _("IP: malloc: %s\n"), strerror(errno));
3746 				free(buf);
3747 				(void) close(sock);
3748 				return (NULL);
3749 			}
3750 
3751 			/* Copy the interface name */
3752 			/*
3753 			 * (void) memcpy(ifname, lifrp->lifr_name,
3754 			 *  sizeof (ifname));
3755 			 * ifname[sizeof (ifname) - 1] = '\0';
3756 			 */
3757 			(void) strcpy(ifname, lifrp->lifr_name);
3758 			break;
3759 		}
3760 	}
3761 
3762 	(void) close(sock);
3763 	free(buf);
3764 
3765 	if (ifname == NULL)
3766 		rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s): none\n",
3767 		    addr);
3768 	else
3769 		rcm_log_message(RCM_TRACE2, "IP: get_mpathd_dest(%s): %s\n",
3770 		    addr, ifname);
3771 
3772 	return (ifname);
3773 }
3774 
3775 static int
3776 if_getcount(int af)
3777 {
3778 	int sock;
3779 	struct lifnum lifn;
3780 
3781 	rcm_log_message(RCM_TRACE1, "IP: if_getcount\n");
3782 
3783 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
3784 		rcm_log_message(RCM_ERROR,
3785 		    _("IP: failure opening %s socket: %s\n"),
3786 		    af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
3787 		return (-1);
3788 	}
3789 
3790 	lifn.lifn_family = af;
3791 	lifn.lifn_flags = 0;
3792 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
3793 		rcm_log_message(RCM_ERROR,
3794 		    _("IP: SIOCLGIFNUM failed: %s\n"),
3795 		    strerror(errno));
3796 		(void) close(sock);
3797 		return (-1);
3798 	}
3799 	(void) close(sock);
3800 
3801 	rcm_log_message(RCM_TRACE1, "IP: if_getcount success: %d\n",
3802 	    lifn.lifn_count);
3803 
3804 	return (lifn.lifn_count);
3805 }
3806 
3807 /*
3808  * tokenize() - turn a command line into tokens; caller is responsible to
3809  *	      provide enough memory to hold all tokens
3810  */
3811 static void
3812 tokenize(char *line, char **tokens, char *tspace, int *ntok)
3813 {
3814 	char *cp;
3815 	char *sp;
3816 
3817 	sp = tspace;
3818 	cp = line;
3819 	for (*ntok = 0; *ntok < MAXARGS; (*ntok)++) {
3820 		tokens[*ntok] = sp;
3821 		while (ISSPACE(*cp))
3822 			cp++;
3823 		if (ISEOL(*cp))
3824 			break;
3825 		do {
3826 			*sp++ = *cp++;
3827 		} while (!ISSPACE(*cp) && !ISEOL(*cp));
3828 
3829 		*sp++ = '\0';
3830 	}
3831 }
3832 
3833 #ifdef RCM_IPMP_DEBUG
3834 
3835 static void
3836 dump_node(ip_cache_t *node)
3837 {
3838 	ip_pif_t *pif;
3839 	ip_lif_t *lif;
3840 
3841 	pif = node->ip_pif;
3842 
3843 	rcm_log_message(RCM_TRACE1, "Node dump:\n");
3844 	rcm_log_message(RCM_TRACE1, "resource = %s\t cache flags = 0x%x\n",
3845 	    node->ip_resource, node->ip_cachestate);
3846 	rcm_log_message(RCM_TRACE1, "ifname = %s\t ifindex = %d\n",
3847 	    pif->pi_ifname, pif->pi_ifindex);
3848 	rcm_log_message(RCM_TRACE1, "groupname = %s\t PPA = %d\n",
3849 	    pif->pi_grpname, pif->pi_ppa);
3850 	if (pif->pi_style == DL_STYLE1) {
3851 		rcm_log_message(RCM_TRACE1, "Provider = DLPI style 1\n");
3852 	}
3853 	if (pif->pi_style == DL_STYLE2) {
3854 		rcm_log_message(RCM_TRACE1, "Provider = DLPI style 2\n");
3855 	};
3856 
3857 	lif = pif->pi_lifs;
3858 
3859 	if (lif == NULL) {
3860 		rcm_log_message(RCM_TRACE1, "No lifs hosted on this device.\n");
3861 		return;
3862 	}
3863 
3864 	rcm_log_message(RCM_TRACE1,
3865 	    "Logical interfaces hosted on this device - \n");
3866 	while (lif != NULL) {
3867 		rcm_log_message(RCM_TRACE1, "\t ifnum = %d \t ifflags = 0x%x",
3868 		    lif->li_ifnum, lif->li_ifflags);
3869 		if (lif->li_addr.family == AF_INET)
3870 			rcm_log_message(RCM_TRACE1, "\t Family = IPv4");
3871 		else if (lif->li_addr.family == AF_INET6)
3872 			rcm_log_message(RCM_TRACE1, "\t Family = IPv6");
3873 		else rcm_log_message(RCM_TRACE1, "\t Family = <Unknown>");
3874 		rcm_log_message(RCM_TRACE1, "\n");
3875 
3876 		lif = lif->li_next;
3877 	}
3878 }
3879 
3880 #else /* !RCM_IPMP_DEBUG */
3881 
3882 /*ARGSUSED*/
3883 static void
3884 dump_node(ip_cache_t *node)
3885 {
3886 	/* do nothing */
3887 }
3888 
3889 #endif /* RCM_IPMP_DEBUG */
3890