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