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