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