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