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