xref: /titanic_52/usr/src/cmd/rcm_daemon/common/ip_rcm.c (revision 1f6352c601b7f3c744b4684ff673c813927da24c)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * This RCM module adds support to the RCM framework for IP managed
28  * interfaces.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <assert.h>
35 #include <string.h>
36 #include <synch.h>
37 #include <libintl.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <sys/types.h>
41 #include <sys/wait.h>
42 #include <sys/stat.h>
43 #include <sys/socket.h>
44 #include <sys/sockio.h>
45 #include <net/if.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <stropts.h>
49 #include <strings.h>
50 #include <sys/sysmacros.h>
51 #include <inet/ip.h>
52 #include <libinetutil.h>
53 #include <libdllink.h>
54 #include <libgen.h>
55 #include <ipmp_admin.h>
56 
57 #include "rcm_module.h"
58 
59 /*
60  * Definitions
61  */
62 #ifndef lint
63 #define	_(x)	gettext(x)
64 #else
65 #define	_(x)	x
66 #endif
67 
68 /* Some generic well-knowns and defaults used in this module */
69 #define	ARP_MOD_NAME		"arp"		/* arp module */
70 #define	IP_MAX_MODS		9		/* max modules pushed on intr */
71 #define	MAX_RECONFIG_SIZE	1024		/* Max. reconfig string size */
72 
73 #define	RCM_LINK_PREFIX		"SUNW_datalink"	/* RCM datalink name prefix */
74 #define	RCM_LINK_RESOURCE_MAX	(13 + LINKID_STR_WIDTH)
75 
76 #define	RCM_STR_SUNW_IP		"SUNW_ip/"	/* IP address export prefix */
77 
78 #define	SBIN_IFCONFIG		"/sbin/ifconfig" /* ifconfig command */
79 #define	SBIN_IFPARSE		"/sbin/ifparse"	/* ifparse command */
80 #define	DHCPFILE_FMT		"/etc/dhcp.%s"	/* DHCP config file */
81 #define	CFGFILE_FMT_IPV4	"/etc/hostname.%s"  /* IPV4 config file */
82 #define	CFGFILE_FMT_IPV6	"/etc/hostname6.%s" /* IPV6 config file */
83 #define	CFG_CMDS_STD	" netmask + broadcast + up" /* Normal config string */
84 #define	CFG_DHCP_CMD		"dhcp wait 0"	/* command to start DHCP */
85 
86 /* Some useful macros */
87 #define	ISSPACE(c)	((c) == ' ' || (c) == '\t')
88 #define	ISEOL(c)	((c) == '\n' || (c) == '\r' || (c) == '\0')
89 #define	STREQ(a, b)	(*(a) == *(b) && strcmp((a), (b)) == 0)
90 
91 /* Interface Cache state flags */
92 #define	CACHE_IF_STALE		0x1		/* stale cached data */
93 #define	CACHE_IF_NEW		0x2		/* new cached interface */
94 #define	CACHE_IF_OFFLINED	0x4		/* interface offlined */
95 #define	CACHE_IF_IGNORE		0x8		/* state held elsewhere */
96 
97 /* Network Cache lookup options */
98 #define	CACHE_NO_REFRESH	0x1		/* cache refresh not needed */
99 #define	CACHE_REFRESH		0x2		/* refresh cache */
100 
101 /* RCM IPMP Module specific property definitions */
102 #define	RCM_IPMP_MIN_REDUNDANCY	1		/* default min. redundancy */
103 
104 /* Stream module operations */
105 #define	MOD_INSERT		0	/* Insert a mid-stream module */
106 #define	MOD_REMOVE		1	/* Remove a mid-stream module */
107 #define	MOD_CHECK		2	/* Check mid-stream module safety */
108 
109 /*
110  * IP module data types
111  */
112 
113 /* Physical interface representation */
114 typedef struct ip_pif {
115 	char		pi_ifname[LIFNAMSIZ];	/* interface name */
116 	char		pi_grname[LIFGRNAMSIZ]; /* IPMP group name */
117 	struct ip_lif	*pi_lifs;		/* ptr to logical interfaces */
118 } ip_pif_t;
119 
120 /* Logical interface representation */
121 typedef struct ip_lif
122 {
123 	struct ip_lif		*li_next;	/* ptr to next lif */
124 	struct ip_lif		*li_prev;  	/* previous next ptr */
125 	ip_pif_t		*li_pif;	/* back ptr to phy int */
126 	ushort_t		li_ifnum;	/* interface number */
127 	union {
128 		sa_family_t		family;
129 		struct sockaddr_storage storage;
130 		struct sockaddr_in	ip4;    /* IPv4 */
131 		struct sockaddr_in6	ip6;    /* IPv6 */
132 	} li_addr;
133 	uint64_t		li_ifflags;	/* current IFF_* flags */
134 	int			li_modcnt;	/* # of modules */
135 	char	*li_modules[IP_MAX_MODS];	/* module list pushed */
136 	char	*li_reconfig;			/* Reconfiguration string */
137 	int32_t			li_cachestate;	/* cache state flags */
138 } ip_lif_t;
139 
140 /* Cache element */
141 typedef struct ip_cache
142 {
143 	struct ip_cache		*ip_next;	/* next cached resource */
144 	struct ip_cache		*ip_prev;	/* prev cached resource */
145 	char			*ip_resource;	/* resource name */
146 	ip_pif_t		*ip_pif;	/* ptr to phy int */
147 	int32_t			ip_ifred;	/* min. redundancy */
148 	int			ip_cachestate;	/* cache state flags */
149 } ip_cache_t;
150 
151 /*
152  * Global cache for network interfaces
153  */
154 static ip_cache_t	cache_head;
155 static ip_cache_t	cache_tail;
156 static mutex_t		cache_lock;
157 static int		events_registered = 0;
158 
159 static dladm_handle_t	dld_handle = NULL;
160 
161 /*
162  * RCM module interface prototypes
163  */
164 static int ip_register(rcm_handle_t *);
165 static int ip_unregister(rcm_handle_t *);
166 static int ip_get_info(rcm_handle_t *, char *, id_t, uint_t,
167 			char **, char **, nvlist_t *, rcm_info_t **);
168 static int ip_suspend(rcm_handle_t *, char *, id_t,
169 			timespec_t *, uint_t, char **, rcm_info_t **);
170 static int ip_resume(rcm_handle_t *, char *, id_t, uint_t,
171 			char **, rcm_info_t **);
172 static int ip_offline(rcm_handle_t *, char *, id_t, uint_t,
173 			char **, rcm_info_t **);
174 static int ip_undo_offline(rcm_handle_t *, char *, id_t, uint_t,
175 			char **, rcm_info_t **);
176 static int ip_remove(rcm_handle_t *, char *, id_t, uint_t,
177 			char **, rcm_info_t **);
178 static int ip_notify_event(rcm_handle_t *, char *, id_t, uint_t,
179 			char **, nvlist_t *, rcm_info_t **);
180 
181 /* Module private routines */
182 static void 	free_cache();
183 static int 	update_cache(rcm_handle_t *);
184 static void 	cache_remove(ip_cache_t *);
185 static ip_cache_t *cache_lookup(rcm_handle_t *, char *, char);
186 static void 	free_node(ip_cache_t *);
187 static void 	cache_insert(ip_cache_t *);
188 static char 	*ip_usage(ip_cache_t *);
189 static int 	update_pif(rcm_handle_t *, int, int, struct lifreq *);
190 static int 	ip_ipmp_offline(ip_cache_t *);
191 static int	ip_ipmp_undo_offline(ip_cache_t *);
192 static int	if_cfginfo(ip_cache_t *, uint_t);
193 static int	if_unplumb(ip_cache_t *);
194 static int	if_replumb(ip_cache_t *);
195 static void 	ip_log_err(ip_cache_t *, char **, char *);
196 static char	*get_link_resource(const char *);
197 static void	clr_cfg_state(ip_pif_t *);
198 static int	modop(char *, char *, int, char);
199 static int	get_modlist(char *, ip_lif_t *);
200 static int	ip_domux2fd(int *, int *, int *, struct lifreq *);
201 static int	ip_plink(int, int, int, struct lifreq *);
202 static int	ip_onlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
203 			rcm_info_t **);
204 static int	ip_offlinelist(rcm_handle_t *, ip_cache_t *, char **, uint_t,
205 			rcm_info_t **);
206 static char 	**ip_get_addrlist(ip_cache_t *);
207 static void	ip_free_addrlist(char **);
208 static void	ip_consumer_notify(rcm_handle_t *, datalink_id_t, char **,
209 			uint_t, rcm_info_t **);
210 static boolean_t ip_addrstr(ip_lif_t *, char *, size_t);
211 
212 static int if_configure(datalink_id_t);
213 static boolean_t isgrouped(const char *);
214 static int if_config_inst(const char *, FILE *, int, boolean_t);
215 static uint_t ntok(const char *cp);
216 static boolean_t ifconfig(const char *, const char *, const char *, boolean_t);
217 
218 /* Module-Private data */
219 static struct rcm_mod_ops ip_ops =
220 {
221 	RCM_MOD_OPS_VERSION,
222 	ip_register,
223 	ip_unregister,
224 	ip_get_info,
225 	ip_suspend,
226 	ip_resume,
227 	ip_offline,
228 	ip_undo_offline,
229 	ip_remove,
230 	NULL,
231 	NULL,
232 	ip_notify_event
233 };
234 
235 /*
236  * rcm_mod_init() - Update registrations, and return the ops structure.
237  */
238 struct rcm_mod_ops *
239 rcm_mod_init(void)
240 {
241 	rcm_log_message(RCM_TRACE1, "IP: mod_init\n");
242 
243 	cache_head.ip_next = &cache_tail;
244 	cache_head.ip_prev = NULL;
245 	cache_tail.ip_prev = &cache_head;
246 	cache_tail.ip_next = NULL;
247 	(void) mutex_init(&cache_lock, NULL, NULL);
248 
249 	(void) dladm_open(&dld_handle);
250 
251 	/* Return the ops vectors */
252 	return (&ip_ops);
253 }
254 
255 /*
256  * rcm_mod_info() - Return a string describing this module.
257  */
258 const char *
259 rcm_mod_info(void)
260 {
261 	rcm_log_message(RCM_TRACE1, "IP: mod_info\n");
262 
263 	return ("IP Multipathing module version 1.23");
264 }
265 
266 /*
267  * rcm_mod_fini() - Destroy the network interfaces cache.
268  */
269 int
270 rcm_mod_fini(void)
271 {
272 	rcm_log_message(RCM_TRACE1, "IP: mod_fini\n");
273 
274 	free_cache();
275 	(void) mutex_destroy(&cache_lock);
276 
277 	dladm_close(dld_handle);
278 	return (RCM_SUCCESS);
279 }
280 
281 /*
282  * ip_register() - Make sure the cache is properly sync'ed, and its
283  *		 registrations are in order.
284  */
285 static int
286 ip_register(rcm_handle_t *hd)
287 {
288 	rcm_log_message(RCM_TRACE1, "IP: register\n");
289 
290 	/* Guard against bad arguments */
291 	assert(hd != NULL);
292 
293 	if (update_cache(hd) < 0)
294 		return (RCM_FAILURE);
295 
296 	/*
297 	 * Need to register interest in all new resources
298 	 * getting attached, so we get attach event notifications
299 	 */
300 	if (!events_registered) {
301 		if (rcm_register_event(hd, RCM_RESOURCE_LINK_NEW, 0, NULL)
302 		    != RCM_SUCCESS) {
303 			rcm_log_message(RCM_ERROR,
304 			    _("IP: failed to register %s\n"),
305 			    RCM_RESOURCE_LINK_NEW);
306 			return (RCM_FAILURE);
307 		} else {
308 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
309 			    RCM_RESOURCE_LINK_NEW);
310 			events_registered++;
311 		}
312 	}
313 
314 	return (RCM_SUCCESS);
315 }
316 
317 /*
318  * ip_unregister() - Walk the cache, unregistering all the networks.
319  */
320 static int
321 ip_unregister(rcm_handle_t *hd)
322 {
323 	ip_cache_t *probe;
324 
325 	rcm_log_message(RCM_TRACE1, "IP: unregister\n");
326 
327 	/* Guard against bad arguments */
328 	assert(hd != NULL);
329 
330 	/* Walk the cache, unregistering everything */
331 	(void) mutex_lock(&cache_lock);
332 	probe = cache_head.ip_next;
333 	while (probe != &cache_tail) {
334 		if (rcm_unregister_interest(hd, probe->ip_resource, 0)
335 		    != RCM_SUCCESS) {
336 			/* unregister failed for whatever reason */
337 			(void) mutex_unlock(&cache_lock);
338 			return (RCM_FAILURE);
339 		}
340 		cache_remove(probe);
341 		free_node(probe);
342 		probe = cache_head.ip_next;
343 	}
344 	(void) mutex_unlock(&cache_lock);
345 
346 	/*
347 	 * Need to unregister interest in all new resources
348 	 */
349 	if (events_registered) {
350 		if (rcm_unregister_event(hd, RCM_RESOURCE_LINK_NEW, 0)
351 		    != RCM_SUCCESS) {
352 			rcm_log_message(RCM_ERROR,
353 			    _("IP: failed to unregister %s\n"),
354 			    RCM_RESOURCE_LINK_NEW);
355 			return (RCM_FAILURE);
356 		} else {
357 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
358 			    RCM_RESOURCE_LINK_NEW);
359 			events_registered--;
360 		}
361 	}
362 
363 	return (RCM_SUCCESS);
364 }
365 
366 /*
367  * ip_offline() - Offline an interface.
368  */
369 static int
370 ip_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
371     char **errorp, rcm_info_t **depend_info)
372 {
373 	ip_cache_t *node;
374 	ip_pif_t *pif;
375 	boolean_t detachable = B_FALSE;
376 	boolean_t ipmp;
377 	int retval;
378 
379 	rcm_log_message(RCM_TRACE1, "IP: offline(%s)\n", rsrc);
380 
381 	/* Guard against bad arguments */
382 	assert(hd != NULL);
383 	assert(rsrc != NULL);
384 	assert(id == (id_t)0);
385 	assert(errorp != NULL);
386 	assert(depend_info != NULL);
387 
388 	/* Lock the cache and lookup the resource */
389 	(void) mutex_lock(&cache_lock);
390 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
391 	if (node == NULL) {
392 		ip_log_err(node, errorp, "Unrecognized resource");
393 		errno = ENOENT;
394 		(void) mutex_unlock(&cache_lock);
395 		return (RCM_SUCCESS);
396 	}
397 
398 	pif = node->ip_pif;
399 
400 	/* Establish default detachability criteria */
401 	if (flags & RCM_FORCE)
402 		detachable = B_TRUE;
403 
404 	/* Check if the interface is under IPMP */
405 	ipmp = (pif->pi_grname[0] != '\0');
406 
407 	/*
408 	 * Even if the interface is not under IPMP, it's possible that it's
409 	 * still okay to offline it as long as there are higher-level failover
410 	 * mechanisms for the addresses it owns (e.g., clustering).  In this
411 	 * case, ip_offlinelist() will return RCM_SUCCESS, and we charge on.
412 	 */
413 	if (!ipmp && !detachable) {
414 		/* Inform consumers of IP addresses being offlined */
415 		if (ip_offlinelist(hd, node, errorp, flags, depend_info) ==
416 		    RCM_SUCCESS) {
417 			rcm_log_message(RCM_DEBUG,
418 			    "IP: consumers agree on detach");
419 		} else {
420 			ip_log_err(node, errorp,
421 			    "Device consumers prohibit offline");
422 			(void) mutex_unlock(&cache_lock);
423 			return (RCM_FAILURE);
424 		}
425 	}
426 
427 	/* Check if it's a query */
428 	if (flags & RCM_QUERY) {
429 		rcm_log_message(RCM_TRACE1, "IP: offline query success(%s)\n",
430 		    rsrc);
431 		(void) mutex_unlock(&cache_lock);
432 		return (RCM_SUCCESS);
433 	}
434 
435 	/* Check detachability, save configuration if detachable */
436 	if (if_cfginfo(node, (flags & RCM_FORCE)) < 0) {
437 		node->ip_cachestate |= CACHE_IF_IGNORE;
438 		rcm_log_message(RCM_TRACE1, "IP: Ignoring node(%s)\n", rsrc);
439 		(void) mutex_unlock(&cache_lock);
440 		return (RCM_SUCCESS);
441 	}
442 
443 	/* standalone detachable device */
444 	if (!ipmp) {
445 		if (if_unplumb(node) < 0) {
446 			ip_log_err(node, errorp,
447 			    "Failed to unplumb the device");
448 
449 			errno = EIO;
450 			(void) mutex_unlock(&cache_lock);
451 			return (RCM_FAILURE);
452 		}
453 
454 		node->ip_cachestate |= CACHE_IF_OFFLINED;
455 		rcm_log_message(RCM_TRACE1, "IP: Offline success(%s)\n", rsrc);
456 		(void) mutex_unlock(&cache_lock);
457 		return (RCM_SUCCESS);
458 	}
459 
460 	/*
461 	 * This is an IPMP interface that can be offlined.
462 	 * Request in.mpathd(1M) to offline the physical interface.
463 	 */
464 	if ((retval = ip_ipmp_offline(node)) != IPMP_SUCCESS)
465 		ip_log_err(node, errorp, "in.mpathd offline failed");
466 
467 	if (retval == IPMP_EMINRED && !detachable) {
468 		/*
469 		 * in.mpathd(1M) could not offline the device because it was
470 		 * the last interface in the group.  However, it's possible
471 		 * that it's still okay to offline it as long as there are
472 		 * higher-level failover mechanisms for the addresses it owns
473 		 * (e.g., clustering).  In this case, ip_offlinelist() will
474 		 * return RCM_SUCCESS, and we charge on.
475 		 */
476 		/* Inform consumers of IP addresses being offlined */
477 		if (ip_offlinelist(hd, node, errorp, flags,
478 		    depend_info) == RCM_SUCCESS) {
479 			rcm_log_message(RCM_DEBUG,
480 			    "IP: consumers agree on detach");
481 		} else {
482 			ip_log_err(node, errorp,
483 			    "Device consumers prohibit offline");
484 			(void) mutex_unlock(&cache_lock);
485 			errno = EBUSY;
486 			return (RCM_FAILURE);
487 		}
488 	}
489 
490 	if (if_unplumb(node) < 0) {
491 		rcm_log_message(RCM_ERROR,
492 		    _("IP: Unplumb failed (%s)\n"),
493 		    pif->pi_ifname);
494 
495 		/* Request in.mpathd to undo the offline */
496 		if (ip_ipmp_undo_offline(node) != IPMP_SUCCESS) {
497 			ip_log_err(node, errorp, "Undo offline failed");
498 			(void) mutex_unlock(&cache_lock);
499 			return (RCM_FAILURE);
500 		}
501 		(void) mutex_unlock(&cache_lock);
502 		return (RCM_FAILURE);
503 	}
504 
505 	node->ip_cachestate |= CACHE_IF_OFFLINED;
506 	rcm_log_message(RCM_TRACE1, "IP: offline success(%s)\n", rsrc);
507 	(void) mutex_unlock(&cache_lock);
508 	return (RCM_SUCCESS);
509 }
510 
511 /*
512  * ip_undo_offline() - Undo offline of a previously offlined device.
513  */
514 /*ARGSUSED*/
515 static int
516 ip_undo_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
517     char **errorp, rcm_info_t **depend_info)
518 {
519 	ip_cache_t *node;
520 
521 	rcm_log_message(RCM_TRACE1, "IP: online(%s)\n", rsrc);
522 
523 	/* Guard against bad arguments */
524 	assert(hd != NULL);
525 	assert(rsrc != NULL);
526 	assert(id == (id_t)0);
527 	assert(errorp != NULL);
528 	assert(depend_info != NULL);
529 
530 	(void) mutex_lock(&cache_lock);
531 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
532 
533 	if (node == NULL) {
534 		ip_log_err(node, errorp, "No such device");
535 		(void) mutex_unlock(&cache_lock);
536 		errno = ENOENT;
537 		return (RCM_FAILURE);
538 	}
539 
540 	/* Check if no attempt should be made to online the device here */
541 	if (node->ip_cachestate & CACHE_IF_IGNORE) {
542 		node->ip_cachestate &= ~(CACHE_IF_IGNORE);
543 		(void) mutex_unlock(&cache_lock);
544 		return (RCM_SUCCESS);
545 	}
546 
547 	/* Check if the interface was previously offlined */
548 	if (!(node->ip_cachestate & CACHE_IF_OFFLINED)) {
549 		ip_log_err(node, errorp, "Device not offlined");
550 		(void) mutex_unlock(&cache_lock);
551 		errno = ENOTSUP;
552 		return (RCM_FAILURE);
553 	}
554 
555 	if (if_replumb(node) == -1) {
556 		/* re-plumb failed */
557 		ip_log_err(node, errorp, "Replumb failed");
558 		(void) mutex_unlock(&cache_lock);
559 		errno = EIO;
560 		return (RCM_FAILURE);
561 
562 	}
563 
564 	/* Inform consumers about IP addresses being un-offlined */
565 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
566 
567 	node->ip_cachestate &= ~(CACHE_IF_OFFLINED);
568 	rcm_log_message(RCM_TRACE1, "IP: online success(%s)\n", rsrc);
569 	(void) mutex_unlock(&cache_lock);
570 	return (RCM_SUCCESS);
571 }
572 
573 /*
574  * ip_get_info() - Gather usage information for this resource.
575  */
576 /*ARGSUSED*/
577 int
578 ip_get_info(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
579     char **usagep, char **errorp, nvlist_t *props, rcm_info_t **depend_info)
580 {
581 	ip_cache_t *node;
582 	char *infostr;
583 
584 	/* Guard against bad arguments */
585 	assert(hd != NULL);
586 	assert(rsrc != NULL);
587 	assert(id == (id_t)0);
588 	assert(usagep != NULL);
589 	assert(errorp != NULL);
590 	assert(depend_info != NULL);
591 
592 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s)\n", rsrc);
593 
594 	(void) mutex_lock(&cache_lock);
595 	node = cache_lookup(hd, rsrc, CACHE_REFRESH);
596 	if (!node) {
597 		rcm_log_message(RCM_INFO,
598 		    _("IP: get_info(%s) unrecognized resource\n"), rsrc);
599 		(void) mutex_unlock(&cache_lock);
600 		errno = ENOENT;
601 		return (RCM_FAILURE);
602 	}
603 
604 	infostr = ip_usage(node);
605 
606 	if (infostr == NULL) {
607 		/* most likely malloc failure */
608 		rcm_log_message(RCM_ERROR,
609 		    _("IP: get_info(%s) malloc failure\n"), rsrc);
610 		(void) mutex_unlock(&cache_lock);
611 		errno = ENOMEM;
612 		*errorp = NULL;
613 		return (RCM_FAILURE);
614 	}
615 
616 	/* Set client/role properties */
617 	(void) nvlist_add_string(props, RCM_CLIENT_NAME, "IP");
618 
619 	/* Set usage property, infostr will be freed by caller */
620 	*usagep = infostr;
621 
622 	rcm_log_message(RCM_TRACE1, "IP: get_info(%s) info = %s \n",
623 	    rsrc, infostr);
624 
625 	(void) mutex_unlock(&cache_lock);
626 	return (RCM_SUCCESS);
627 }
628 
629 /*
630  * ip_suspend() - Nothing to do, always okay
631  */
632 /*ARGSUSED*/
633 static int
634 ip_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
635 			uint_t flags, char **errorp, rcm_info_t **depend_info)
636 {
637 	/* Guard against bad arguments */
638 	assert(hd != NULL);
639 	assert(rsrc != NULL);
640 	assert(id == (id_t)0);
641 	assert(interval != NULL);
642 	assert(errorp != NULL);
643 	assert(depend_info != NULL);
644 
645 	rcm_log_message(RCM_TRACE1, "IP: suspend(%s)\n", rsrc);
646 	return (RCM_SUCCESS);
647 }
648 
649 /*
650  * ip_resume() - Nothing to do, always okay
651  */
652 /*ARGSUSED*/
653 static int
654 ip_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
655 		char **errorp, rcm_info_t ** depend_info)
656 {
657 	/* Guard against bad arguments */
658 	assert(hd != NULL);
659 	assert(rsrc != NULL);
660 	assert(id == (id_t)0);
661 	assert(errorp != NULL);
662 	assert(depend_info != NULL);
663 
664 	rcm_log_message(RCM_TRACE1, "IP: resume(%s)\n", rsrc);
665 
666 	return (RCM_SUCCESS);
667 }
668 
669 /*
670  * ip_remove() - remove a resource from cache
671  */
672 /*ARGSUSED*/
673 static int
674 ip_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
675 		char **errorp, rcm_info_t **depend_info)
676 {
677 	ip_cache_t *node;
678 
679 	/* Guard against bad arguments */
680 	assert(hd != NULL);
681 	assert(rsrc != NULL);
682 	assert(id == (id_t)0);
683 	assert(errorp != NULL);
684 	assert(depend_info != NULL);
685 
686 	rcm_log_message(RCM_TRACE1, "IP: remove(%s)\n", rsrc);
687 
688 	(void) mutex_lock(&cache_lock);
689 	node = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
690 	if (!node) {
691 		rcm_log_message(RCM_INFO,
692 		    _("IP: remove(%s) unrecognized resource\n"), rsrc);
693 		(void) mutex_unlock(&cache_lock);
694 		errno = ENOENT;
695 		return (RCM_FAILURE);
696 	}
697 
698 	/* remove the cached entry for the resource */
699 	cache_remove(node);
700 	free_node(node);
701 
702 	(void) mutex_unlock(&cache_lock);
703 	return (RCM_SUCCESS);
704 }
705 
706 /*
707  * ip_notify_event - Project private implementation to receive new resource
708  *		   events. It intercepts all new resource events. If the
709  *		   new resource is a network resource, pass up a notify
710  *		   for it too. The new resource need not be cached, since
711  *		   it is done at register again.
712  */
713 /*ARGSUSED*/
714 static int
715 ip_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
716 			char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
717 {
718 	datalink_id_t	linkid;
719 	nvpair_t *nvp = NULL;
720 	uint64_t id64;
721 
722 	assert(hd != NULL);
723 	assert(rsrc != NULL);
724 	assert(id == (id_t)0);
725 	assert(nvl != NULL);
726 
727 	rcm_log_message(RCM_TRACE1, "IP: notify_event(%s)\n", rsrc);
728 
729 	if (!STREQ(rsrc, RCM_RESOURCE_LINK_NEW)) {
730 		rcm_log_message(RCM_INFO,
731 		    _("IP: unrecognized event for %s\n"), rsrc);
732 		ip_log_err(NULL, errorp, "unrecognized event");
733 		errno = EINVAL;
734 		return (RCM_FAILURE);
735 	}
736 
737 	/* Update cache to reflect latest interfaces */
738 	if (update_cache(hd) < 0) {
739 		rcm_log_message(RCM_ERROR, _("IP: update_cache failed\n"));
740 		ip_log_err(NULL, errorp, "Private Cache update failed");
741 		return (RCM_FAILURE);
742 	}
743 
744 	rcm_log_message(RCM_TRACE1, "IP: process_nvlist\n");
745 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
746 		if (STREQ(nvpair_name(nvp), RCM_NV_LINKID)) {
747 			if (nvpair_value_uint64(nvp, &id64) != 0) {
748 				rcm_log_message(RCM_WARNING,
749 				    _("IP: cannot get linkid\n"));
750 				return (RCM_FAILURE);
751 			}
752 			linkid = (datalink_id_t)id64;
753 			if (if_configure(linkid) != 0) {
754 				rcm_log_message(RCM_ERROR,
755 				    _("IP: Configuration failed (%u)\n"),
756 				    linkid);
757 				ip_log_err(NULL, errorp,
758 				    "Failed configuring one or more IP "
759 				    "addresses");
760 			}
761 
762 			/* Notify all IP address consumers */
763 			ip_consumer_notify(hd, linkid, errorp, flags,
764 			    depend_info);
765 		}
766 	}
767 
768 	rcm_log_message(RCM_TRACE1,
769 	    "IP: notify_event: device configuration complete\n");
770 
771 	return (RCM_SUCCESS);
772 }
773 
774 /*
775  * ip_usage - Determine the usage of a device.  Call with cache_lock held.
776  *	    The returned buffer is owned by caller, and the caller
777  *	    must free it up when done.
778  */
779 static char *
780 ip_usage(ip_cache_t *node)
781 {
782 	ip_lif_t *lif;
783 	uint_t numup;
784 	char *sep, *buf, *linkidstr;
785 	datalink_id_t linkid;
786 	const char *msg;
787 	char link[MAXLINKNAMELEN];
788 	char addrstr[INET6_ADDRSTRLEN];
789 	char errmsg[DLADM_STRSIZE];
790 	dladm_status_t status;
791 	boolean_t offline, ipmp;
792 	size_t bufsz = 0;
793 
794 	rcm_log_message(RCM_TRACE2, "IP: usage(%s)\n", node->ip_resource);
795 
796 	/*
797 	 * Note that node->ip_resource is in the form of SUNW_datalink/<linkid>
798 	 */
799 	linkidstr = strchr(node->ip_resource, '/');
800 	assert(linkidstr != NULL);
801 	linkidstr = linkidstr ? linkidstr + 1 : node->ip_resource;
802 
803 	errno = 0;
804 	linkid = strtol(linkidstr, &buf, 10);
805 	if (errno != 0 || *buf != '\0') {
806 		rcm_log_message(RCM_ERROR,
807 		    _("IP: usage(%s) parse linkid failure (%s)\n"),
808 		    node->ip_resource, strerror(errno));
809 		return (NULL);
810 	}
811 
812 	if ((status = dladm_datalink_id2info(dld_handle, linkid, NULL, NULL,
813 	    NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
814 		rcm_log_message(RCM_ERROR,
815 		    _("IP: usage(%s) get link name failure(%s)\n"),
816 		    node->ip_resource, dladm_status2str(status, errmsg));
817 		return (NULL);
818 	}
819 
820 	/* TRANSLATION_NOTE: separator used between IP addresses */
821 	sep = _(", ");
822 
823 	numup = 0;
824 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next)
825 		if (lif->li_ifflags & IFF_UP)
826 			numup++;
827 
828 	ipmp = (node->ip_pif->pi_grname[0] != '\0');
829 	offline = ((node->ip_cachestate & CACHE_IF_OFFLINED) != 0);
830 
831 	if (offline) {
832 		msg = _("offlined");
833 	} else if (numup == 0) {
834 		msg = _("plumbed but down");
835 	} else {
836 		if (ipmp) {
837 			msg = _("providing connectivity for IPMP group ");
838 			bufsz += LIFGRNAMSIZ;
839 		} else {
840 			msg = _("hosts IP addresses: ");
841 			bufsz += (numup * (INET6_ADDRSTRLEN + strlen(sep)));
842 		}
843 	}
844 
845 	bufsz += strlen(link) + strlen(msg) + 1;
846 	if ((buf = malloc(bufsz)) == NULL) {
847 		rcm_log_message(RCM_ERROR,
848 		    _("IP: usage(%s) malloc failure(%s)\n"),
849 		    node->ip_resource, strerror(errno));
850 		return (NULL);
851 	}
852 	(void) snprintf(buf, bufsz, "%s: %s", link, msg);
853 
854 	if (!offline && numup > 0) {
855 		if (ipmp) {
856 			(void) strlcat(buf, node->ip_pif->pi_grname, bufsz);
857 		} else {
858 			lif = node->ip_pif->pi_lifs;
859 			for (; lif != NULL; lif = lif->li_next) {
860 				if (!(lif->li_ifflags & IFF_UP))
861 					continue;
862 
863 				if (!ip_addrstr(lif, addrstr, sizeof (addrstr)))
864 					continue;
865 
866 				(void) strlcat(buf, addrstr, bufsz);
867 				if (--numup > 0)
868 					(void) strlcat(buf, sep, bufsz);
869 			}
870 		}
871 	}
872 
873 	rcm_log_message(RCM_TRACE2, "IP: usage (%s) info = %s\n",
874 	    node->ip_resource, buf);
875 
876 	return (buf);
877 }
878 
879 static boolean_t
880 ip_addrstr(ip_lif_t *lif, char *addrstr, size_t addrsize)
881 {
882 	int af = lif->li_addr.family;
883 	void *addr;
884 
885 	if (af == AF_INET6) {
886 		addr = &lif->li_addr.ip6.sin6_addr;
887 	} else if (af == AF_INET) {
888 		addr = &lif->li_addr.ip4.sin_addr;
889 	} else {
890 		rcm_log_message(RCM_DEBUG,
891 		    "IP: unknown addr family %d, assuming AF_INET\n", af);
892 		af = AF_INET;
893 		addr = &lif->li_addr.ip4.sin_addr;
894 	}
895 	if (inet_ntop(af, addr, addrstr, addrsize) == NULL) {
896 		rcm_log_message(RCM_ERROR,
897 		    _("IP: inet_ntop: %s\n"), strerror(errno));
898 		return (B_FALSE);
899 	}
900 
901 	rcm_log_message(RCM_DEBUG, "IP addr := %s\n", addrstr);
902 	return (B_TRUE);
903 }
904 
905 /*
906  * Cache management routines, all cache management functions should be
907  * be called with cache_lock held.
908  */
909 
910 /*
911  * cache_lookup() - Get a cache node for a resource.
912  *		  Call with cache lock held.
913  *
914  * This ensures that the cache is consistent with the system state and
915  * returns a pointer to the cache element corresponding to the resource.
916  */
917 static ip_cache_t *
918 cache_lookup(rcm_handle_t *hd, char *rsrc, char options)
919 {
920 	ip_cache_t *probe;
921 
922 	rcm_log_message(RCM_TRACE2, "IP: cache lookup(%s)\n", rsrc);
923 
924 	if ((options & CACHE_REFRESH) && (hd != NULL)) {
925 		/* drop lock since update locks cache again */
926 		(void) mutex_unlock(&cache_lock);
927 		(void) update_cache(hd);
928 		(void) mutex_lock(&cache_lock);
929 	}
930 
931 	probe = cache_head.ip_next;
932 	while (probe != &cache_tail) {
933 		if (probe->ip_resource &&
934 		    STREQ(rsrc, probe->ip_resource)) {
935 			rcm_log_message(RCM_TRACE2,
936 			    "IP: cache lookup success(%s)\n", rsrc);
937 			return (probe);
938 		}
939 		probe = probe->ip_next;
940 	}
941 	return (NULL);
942 }
943 
944 /*
945  * free_node - Free a node from the cache
946  *	     Call with cache_lock held.
947  */
948 static void
949 free_node(ip_cache_t *node)
950 {
951 	ip_pif_t *pif;
952 	ip_lif_t *lif, *tmplif;
953 
954 	if (node) {
955 		if (node->ip_resource) {
956 			free(node->ip_resource);
957 		}
958 
959 		/* free the pif */
960 		pif = node->ip_pif;
961 		if (pif) {
962 			/* free logical interfaces */
963 			lif = pif->pi_lifs;
964 			while (lif) {
965 				tmplif = lif->li_next;
966 				free(lif);
967 				lif = tmplif;
968 			}
969 			free(pif);
970 		}
971 		free(node);
972 	}
973 }
974 
975 /*
976  * cache_insert - Insert a resource node in cache
977  *		Call with the cache_lock held.
978  */
979 static void
980 cache_insert(ip_cache_t *node)
981 {
982 	rcm_log_message(RCM_TRACE2, "IP: cache insert(%s)\n",
983 	    node->ip_resource);
984 
985 	/* insert at the head for best performance */
986 	node->ip_next = cache_head.ip_next;
987 	node->ip_prev = &cache_head;
988 
989 	node->ip_next->ip_prev = node;
990 	node->ip_prev->ip_next = node;
991 }
992 
993 /*
994  * cache_remove() - Remove a resource node from cache.
995  *		  Call with the cache_lock held.
996  */
997 static void
998 cache_remove(ip_cache_t *node)
999 {
1000 	rcm_log_message(RCM_TRACE2, "IP: cache remove(%s)\n",
1001 	    node->ip_resource);
1002 
1003 	node->ip_next->ip_prev = node->ip_prev;
1004 	node->ip_prev->ip_next = node->ip_next;
1005 	node->ip_next = NULL;
1006 	node->ip_prev = NULL;
1007 }
1008 
1009 /*
1010  * update_pif() - Update physical interface properties
1011  *		Call with cache_lock held
1012  */
1013 /*ARGSUSED*/
1014 static int
1015 update_pif(rcm_handle_t *hd, int af, int sock, struct lifreq *lifr)
1016 {
1017 	char *rsrc;
1018 	ifspec_t ifspec;
1019 	ushort_t ifnumber = 0;
1020 	ip_cache_t *probe;
1021 	ip_pif_t pif;
1022 	ip_pif_t *probepif;
1023 	ip_lif_t *probelif;
1024 	struct lifreq lifreq;
1025 	struct sockaddr_storage ifaddr;
1026 	uint64_t ifflags;
1027 	int lif_listed = 0;
1028 
1029 	rcm_log_message(RCM_TRACE1, "IP: update_pif(%s)\n", lifr->lifr_name);
1030 
1031 	if (!ifparse_ifspec(lifr->lifr_name, &ifspec)) {
1032 		rcm_log_message(RCM_ERROR, _("IP: bad network interface: %s\n"),
1033 		    lifr->lifr_name);
1034 		return (-1);
1035 	}
1036 
1037 	(void) snprintf(pif.pi_ifname, sizeof (pif.pi_ifname), "%s%d",
1038 	    ifspec.ifsp_devnm, ifspec.ifsp_ppa);
1039 	if (ifspec.ifsp_lunvalid)
1040 		ifnumber = ifspec.ifsp_lun;
1041 
1042 	/* Get the interface flags */
1043 	(void) strlcpy(lifreq.lifr_name, lifr->lifr_name, LIFNAMSIZ);
1044 	if (ioctl(sock, SIOCGLIFFLAGS, (char *)&lifreq) < 0) {
1045 		if (errno != ENXIO) {
1046 			rcm_log_message(RCM_ERROR,
1047 			    _("IP: SIOCGLIFFLAGS(%s): %s\n"),
1048 			    lifreq.lifr_name, strerror(errno));
1049 		}
1050 		return (-1);
1051 	}
1052 	(void) memcpy(&ifflags, &lifreq.lifr_flags, sizeof (ifflags));
1053 
1054 	/*
1055 	 * Ignore interfaces that are always incapable of DR:
1056 	 *   - IFF_VIRTUAL:	e.g., loopback and vni
1057 	 *   - IFF_POINTOPOINT:	e.g., sppp and ip.tun
1058 	 *   - !IFF_MULTICAST:	e.g., ip.6to4tun
1059 	 *   - IFF_IPMP:	IPMP meta-interfaces
1060 	 *
1061 	 * Note: The !IFF_MULTICAST check can be removed once iptun is
1062 	 * implemented as a datalink.
1063 	 */
1064 	if (!(ifflags & IFF_MULTICAST) ||
1065 	    (ifflags & (IFF_POINTOPOINT | IFF_VIRTUAL | IFF_IPMP))) {
1066 		rcm_log_message(RCM_TRACE3, "IP: if ignored (%s)\n",
1067 		    pif.pi_ifname);
1068 		return (0);
1069 	}
1070 
1071 	/* Get the interface group name for this interface */
1072 	if (ioctl(sock, SIOCGLIFGROUPNAME, (char *)&lifreq) < 0) {
1073 		if (errno != ENXIO) {
1074 			rcm_log_message(RCM_ERROR,
1075 			    _("IP: SIOCGLIFGROUPNAME(%s): %s\n"),
1076 			    lifreq.lifr_name, strerror(errno));
1077 		}
1078 		return (-1);
1079 	}
1080 
1081 	/* copy the group name */
1082 	(void) strlcpy(pif.pi_grname, lifreq.lifr_groupname,
1083 	    sizeof (pif.pi_grname));
1084 
1085 	/* Get the interface address for this interface */
1086 	if (ioctl(sock, SIOCGLIFADDR, (char *)&lifreq) < 0) {
1087 		if (errno != ENXIO) {
1088 			rcm_log_message(RCM_ERROR,
1089 			    _("IP: SIOCGLIFADDR(%s): %s\n"),
1090 			    lifreq.lifr_name, strerror(errno));
1091 			return (-1);
1092 		}
1093 	}
1094 	(void) memcpy(&ifaddr, &lifreq.lifr_addr, sizeof (ifaddr));
1095 
1096 	rsrc = get_link_resource(pif.pi_ifname);
1097 	if (rsrc == NULL) {
1098 		rcm_log_message(RCM_ERROR,
1099 		    _("IP: get_link_resource(%s) failed\n"),
1100 		    lifreq.lifr_name);
1101 		return (-1);
1102 	}
1103 
1104 	probe = cache_lookup(hd, rsrc, CACHE_NO_REFRESH);
1105 	if (probe != NULL) {
1106 		free(rsrc);
1107 		probe->ip_cachestate &= ~(CACHE_IF_STALE);
1108 	} else {
1109 		if ((probe = calloc(1, sizeof (ip_cache_t))) == NULL) {
1110 			/* malloc errors are bad */
1111 			free(rsrc);
1112 			rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1113 			    strerror(errno));
1114 			return (-1);
1115 		}
1116 
1117 		probe->ip_resource = rsrc;
1118 		probe->ip_pif = NULL;
1119 		probe->ip_ifred = RCM_IPMP_MIN_REDUNDANCY;
1120 		probe->ip_cachestate |= CACHE_IF_NEW;
1121 
1122 		cache_insert(probe);
1123 	}
1124 
1125 	probepif = probe->ip_pif;
1126 	if (probepif != NULL) {
1127 		/* Check if lifs need to be updated */
1128 		probelif = probepif->pi_lifs;
1129 		while (probelif != NULL) {
1130 			if ((probelif->li_ifnum == ifnumber) &&
1131 			    (probelif->li_addr.family == ifaddr.ss_family)) {
1132 
1133 				rcm_log_message(RCM_TRACE2,
1134 				    "IP: refreshing lifs for %s, ifnum=%d\n",
1135 				    pif.pi_ifname, probelif->li_ifnum);
1136 
1137 				/* refresh lif properties */
1138 				(void) memcpy(&probelif->li_addr, &ifaddr,
1139 				    sizeof (probelif->li_addr));
1140 
1141 				probelif->li_ifflags = ifflags;
1142 
1143 				lif_listed++;
1144 				probelif->li_cachestate &= ~(CACHE_IF_STALE);
1145 				break;
1146 			}
1147 			probelif = probelif->li_next;
1148 		}
1149 	}
1150 
1151 	if (probepif == NULL) {
1152 		if ((probepif = calloc(1, sizeof (ip_pif_t))) == NULL) {
1153 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1154 			    strerror(errno));
1155 			if (probe->ip_pif == NULL) {
1156 				/* we created it, so clean it up */
1157 				free(probe);
1158 			}
1159 			return (-1);
1160 		}
1161 
1162 		probe->ip_pif = probepif;
1163 
1164 		/* Save interface name */
1165 		(void) memcpy(&probepif->pi_ifname, &pif.pi_ifname,
1166 		    sizeof (pif.pi_ifname));
1167 	}
1168 
1169 	/* save the group name */
1170 	(void) strlcpy(probepif->pi_grname, pif.pi_grname,
1171 	    sizeof (pif.pi_grname));
1172 
1173 	/* add lif, if this is a lif and it is not in cache */
1174 	if (!lif_listed) {
1175 		rcm_log_message(RCM_TRACE2, "IP: adding lifs to %s\n",
1176 		    pif.pi_ifname);
1177 
1178 		if ((probelif = calloc(1, sizeof (ip_lif_t))) == NULL) {
1179 			rcm_log_message(RCM_ERROR, _("IP: malloc: %s\n"),
1180 			    strerror(errno));
1181 			return (-1);
1182 		}
1183 
1184 		/* save lif properties */
1185 		(void) memcpy(&probelif->li_addr, &ifaddr,
1186 		    sizeof (probelif->li_addr));
1187 
1188 		probelif->li_ifnum = ifnumber;
1189 		probelif->li_ifflags = ifflags;
1190 
1191 		/* insert us at the head of the lif list */
1192 		probelif->li_next = probepif->pi_lifs;
1193 		if (probelif->li_next != NULL) {
1194 			probelif->li_next->li_prev = probelif;
1195 		}
1196 		probelif->li_prev = NULL;
1197 		probelif->li_pif = probepif;
1198 
1199 		probepif->pi_lifs = probelif;
1200 	}
1201 
1202 	rcm_log_message(RCM_TRACE3, "IP: update_pif: (%s) success\n",
1203 	    probe->ip_resource);
1204 
1205 	return (0);
1206 }
1207 
1208 /*
1209  * update_ipifs() - Determine all network interfaces in the system
1210  *		  Call with cache_lock held
1211  */
1212 static int
1213 update_ipifs(rcm_handle_t *hd, int af)
1214 {
1215 	int sock;
1216 	char *buf;
1217 	struct lifnum lifn;
1218 	struct lifconf lifc;
1219 	struct lifreq *lifrp;
1220 	int i;
1221 
1222 	rcm_log_message(RCM_TRACE2, "IP: update_ipifs\n");
1223 
1224 	if ((sock = socket(af, SOCK_DGRAM, 0)) == -1) {
1225 		rcm_log_message(RCM_ERROR,
1226 		    _("IP: failure opening %s socket: %s\n"),
1227 		    af == AF_INET6 ? "IPv6" : "IPv4", strerror(errno));
1228 		return (-1);
1229 	}
1230 
1231 	lifn.lifn_family = af;
1232 	lifn.lifn_flags = LIFC_UNDER_IPMP;
1233 	if (ioctl(sock, SIOCGLIFNUM, (char *)&lifn) < 0) {
1234 		rcm_log_message(RCM_ERROR,
1235 		    _("IP: SIOCLGIFNUM failed: %s\n"),
1236 		    strerror(errno));
1237 		(void) close(sock);
1238 		return (-1);
1239 	}
1240 
1241 	if ((buf = calloc(lifn.lifn_count, sizeof (struct lifreq))) == NULL) {
1242 		rcm_log_message(RCM_ERROR, _("IP: calloc: %s\n"),
1243 		    strerror(errno));
1244 		(void) close(sock);
1245 		return (-1);
1246 	}
1247 
1248 	lifc.lifc_family = af;
1249 	lifc.lifc_flags = LIFC_UNDER_IPMP;
1250 	lifc.lifc_len = sizeof (struct lifreq) * lifn.lifn_count;
1251 	lifc.lifc_buf = buf;
1252 
1253 	if (ioctl(sock, SIOCGLIFCONF, (char *)&lifc) < 0) {
1254 		rcm_log_message(RCM_ERROR,
1255 		    _("IP: SIOCGLIFCONF failed: %s\n"),
1256 		    strerror(errno));
1257 		free(buf);
1258 		(void) close(sock);
1259 		return (-1);
1260 	}
1261 
1262 	/* now we need to search for active interfaces */
1263 	lifrp = lifc.lifc_req;
1264 	for (i = 0; i < lifn.lifn_count; i++) {
1265 		(void) update_pif(hd, af, sock, lifrp);
1266 		lifrp++;
1267 	}
1268 
1269 	free(buf);
1270 	(void) close(sock);
1271 	return (0);
1272 }
1273 
1274 /*
1275  * update_cache() - Update cache with latest interface info
1276  */
1277 static int
1278 update_cache(rcm_handle_t *hd)
1279 {
1280 	ip_cache_t *probe;
1281 	struct ip_lif *lif;
1282 	struct ip_lif *nextlif;
1283 	int rv;
1284 	int i;
1285 
1286 	rcm_log_message(RCM_TRACE2, "IP: update_cache\n");
1287 
1288 	(void) mutex_lock(&cache_lock);
1289 
1290 	/* first we walk the entire cache, marking each entry stale */
1291 	probe = cache_head.ip_next;
1292 	while (probe != &cache_tail) {
1293 		probe->ip_cachestate |= CACHE_IF_STALE;
1294 		if ((probe->ip_pif != NULL) &&
1295 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1296 			while (lif != NULL) {
1297 				lif->li_cachestate |= CACHE_IF_STALE;
1298 				lif = lif->li_next;
1299 			}
1300 		}
1301 		probe = probe->ip_next;
1302 	}
1303 
1304 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv4 interfaces\n");
1305 	if (update_ipifs(hd, AF_INET) < 0) {
1306 		(void) mutex_unlock(&cache_lock);
1307 		return (-1);
1308 	}
1309 
1310 	rcm_log_message(RCM_TRACE2, "IP: scanning IPv6 interfaces\n");
1311 	if (update_ipifs(hd, AF_INET6) < 0) {
1312 		(void) mutex_unlock(&cache_lock);
1313 		return (-1);
1314 	}
1315 
1316 	probe = cache_head.ip_next;
1317 	/* unregister devices that are not offlined and still in cache */
1318 	while (probe != &cache_tail) {
1319 		ip_cache_t *freeit;
1320 		if ((probe->ip_pif != NULL) &&
1321 		    ((lif = probe->ip_pif->pi_lifs) != NULL)) {
1322 			/* clear stale lifs */
1323 			while (lif != NULL) {
1324 				if (lif->li_cachestate & CACHE_IF_STALE) {
1325 					nextlif = lif->li_next;
1326 					if (lif->li_prev != NULL)
1327 						lif->li_prev->li_next = nextlif;
1328 					if (nextlif != NULL)
1329 						nextlif->li_prev = lif->li_prev;
1330 					if (probe->ip_pif->pi_lifs == lif)
1331 						probe->ip_pif->pi_lifs =
1332 						    nextlif;
1333 					for (i = 0; i < IP_MAX_MODS; i++) {
1334 						free(lif->li_modules[i]);
1335 					}
1336 					free(lif->li_reconfig);
1337 					free(lif);
1338 					lif = nextlif;
1339 				} else {
1340 					lif = lif->li_next;
1341 				}
1342 			}
1343 		}
1344 		if ((probe->ip_cachestate & CACHE_IF_STALE) &&
1345 		    !(probe->ip_cachestate & CACHE_IF_OFFLINED)) {
1346 			(void) rcm_unregister_interest(hd, probe->ip_resource,
1347 			    0);
1348 			rcm_log_message(RCM_DEBUG, "IP: unregistered %s\n",
1349 			    probe->ip_resource);
1350 			freeit = probe;
1351 			probe = probe->ip_next;
1352 			cache_remove(freeit);
1353 			free_node(freeit);
1354 			continue;
1355 		}
1356 
1357 		if (!(probe->ip_cachestate & CACHE_IF_NEW)) {
1358 			probe = probe->ip_next;
1359 			continue;
1360 		}
1361 
1362 		rv = rcm_register_interest(hd, probe->ip_resource, 0, NULL);
1363 		if (rv != RCM_SUCCESS) {
1364 			rcm_log_message(RCM_ERROR,
1365 			    _("IP: failed to register %s\n"),
1366 			    probe->ip_resource);
1367 			(void) mutex_unlock(&cache_lock);
1368 			return (-1);
1369 		} else {
1370 			rcm_log_message(RCM_DEBUG, "IP: registered %s\n",
1371 			    probe->ip_resource);
1372 			probe->ip_cachestate &= ~(CACHE_IF_NEW);
1373 		}
1374 		probe = probe->ip_next;
1375 	}
1376 
1377 	(void) mutex_unlock(&cache_lock);
1378 	return (0);
1379 }
1380 
1381 /*
1382  * free_cache() - Empty the cache
1383  */
1384 static void
1385 free_cache()
1386 {
1387 	ip_cache_t *probe;
1388 
1389 	rcm_log_message(RCM_TRACE2, "IP: free_cache\n");
1390 
1391 	(void) mutex_lock(&cache_lock);
1392 	probe = cache_head.ip_next;
1393 	while (probe != &cache_tail) {
1394 		cache_remove(probe);
1395 		free_node(probe);
1396 		probe = cache_head.ip_next;
1397 	}
1398 	(void) mutex_unlock(&cache_lock);
1399 }
1400 
1401 /*
1402  * ip_log_err() - RCM error log wrapper
1403  */
1404 static void
1405 ip_log_err(ip_cache_t *node, char **errorp, char *errmsg)
1406 {
1407 	char *ifname = NULL;
1408 	int size;
1409 	const char *errfmt;
1410 	char *error = NULL;
1411 
1412 	if ((node != NULL) && (node->ip_pif != NULL) &&
1413 	    (node->ip_pif->pi_ifname != NULL)) {
1414 		ifname = node->ip_pif->pi_ifname;
1415 	}
1416 
1417 	if (ifname == NULL) {
1418 		rcm_log_message(RCM_ERROR, _("IP: %s\n"), errmsg);
1419 		errfmt = _("IP: %s");
1420 		size = strlen(errfmt) + strlen(errmsg) + 1;
1421 		if (errorp != NULL && (error = malloc(size)) != NULL)
1422 			(void) snprintf(error, size, errfmt, errmsg);
1423 	} else {
1424 		rcm_log_message(RCM_ERROR, _("IP: %s(%s)\n"), errmsg, ifname);
1425 		errfmt = _("IP: %s(%s)");
1426 		size = strlen(errfmt) + strlen(errmsg) + strlen(ifname) + 1;
1427 		if (errorp != NULL && (error = malloc(size)) != NULL)
1428 			(void) snprintf(error, size, errfmt, errmsg, ifname);
1429 	}
1430 
1431 	if (errorp != NULL)
1432 		*errorp = error;
1433 }
1434 
1435 /*
1436  * if_cfginfo() - Save off the config info for all interfaces
1437  */
1438 static int
1439 if_cfginfo(ip_cache_t *node, uint_t force)
1440 {
1441 	ip_lif_t *lif;
1442 	ip_pif_t *pif;
1443 	int i;
1444 	FILE *fp;
1445 	char syscmd[MAX_RECONFIG_SIZE + LIFNAMSIZ];
1446 	char buf[MAX_RECONFIG_SIZE];
1447 
1448 	rcm_log_message(RCM_TRACE2, "IP: if_cfginfo(%s)\n", node->ip_resource);
1449 
1450 	pif = node->ip_pif;
1451 	lif = pif->pi_lifs;
1452 
1453 	while (lif != NULL) {
1454 		/* Make a list of modules pushed and save */
1455 		if (lif->li_ifnum == 0) {	/* physical instance */
1456 			if (get_modlist(pif->pi_ifname, lif) == -1) {
1457 				rcm_log_message(RCM_ERROR,
1458 				    _("IP: get modlist error (%s) %s\n"),
1459 				    pif->pi_ifname, strerror(errno));
1460 				clr_cfg_state(pif);
1461 				return (-1);
1462 			}
1463 
1464 			if (!force) {
1465 				/* Look if unknown modules have been inserted */
1466 				for (i = (lif->li_modcnt - 2); i > 0; i--) {
1467 					if (modop(pif->pi_ifname,
1468 					    lif->li_modules[i],
1469 					    i, MOD_CHECK) == -1) {
1470 						rcm_log_message(RCM_ERROR,
1471 						    _("IP: module %s@%d\n"),
1472 						    lif->li_modules[i], i);
1473 						clr_cfg_state(pif);
1474 						return (-1);
1475 					}
1476 				}
1477 			}
1478 
1479 			/* Last module is the device driver, so ignore that */
1480 			for (i = (lif->li_modcnt - 2); i > 0; i--) {
1481 				rcm_log_message(RCM_TRACE2,
1482 				    "IP: modremove Pos = %d, Module = %s \n",
1483 				    i, lif->li_modules[i]);
1484 				if (modop(pif->pi_ifname, lif->li_modules[i],
1485 				    i, MOD_REMOVE) == -1) {
1486 					while (i != (lif->li_modcnt - 2)) {
1487 						if (modop(pif->pi_ifname,
1488 						    lif->li_modules[i],
1489 						    i, MOD_INSERT) == -1) {
1490 							/* Gross error */
1491 							rcm_log_message(
1492 							    RCM_ERROR,
1493 							    _("IP: if_cfginfo"
1494 							    "(%s) %s\n"),
1495 							    pif->pi_ifname,
1496 							    strerror(errno));
1497 							clr_cfg_state(pif);
1498 							return (-1);
1499 						}
1500 						i++;
1501 					}
1502 					rcm_log_message(
1503 					    RCM_ERROR,
1504 					    _("IP: if_cfginfo(%s): modremove "
1505 					    "%s failed: %s\n"), pif->pi_ifname,
1506 					    lif->li_modules[i],
1507 					    strerror(errno));
1508 					clr_cfg_state(pif);
1509 					return (-1);
1510 				}
1511 			}
1512 		}
1513 
1514 		/* Save reconfiguration information */
1515 		if (lif->li_ifflags & IFF_IPV4) {
1516 			(void) snprintf(syscmd, sizeof (syscmd),
1517 			    "%s %s:%d configinfo\n", SBIN_IFCONFIG,
1518 			    pif->pi_ifname, lif->li_ifnum);
1519 		} else if (lif->li_ifflags & IFF_IPV6) {
1520 			(void) snprintf(syscmd, sizeof (syscmd),
1521 			    "%s %s:%d inet6 configinfo\n", SBIN_IFCONFIG,
1522 			    pif->pi_ifname, lif->li_ifnum);
1523 		}
1524 		rcm_log_message(RCM_TRACE2, "IP: %s\n", syscmd);
1525 
1526 		/* open a pipe to retrieve reconfiguration info */
1527 		if ((fp = popen(syscmd, "r")) == NULL) {
1528 			rcm_log_message(RCM_ERROR,
1529 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1530 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
1531 			clr_cfg_state(pif);
1532 			return (-1);
1533 		}
1534 		bzero(buf, MAX_RECONFIG_SIZE);
1535 
1536 		if (fgets(buf, MAX_RECONFIG_SIZE, fp) == NULL) {
1537 			rcm_log_message(RCM_ERROR,
1538 			    _("IP: ifconfig configinfo error (%s:%d) %s\n"),
1539 			    pif->pi_ifname, lif->li_ifnum, strerror(errno));
1540 			(void) pclose(fp);
1541 			clr_cfg_state(pif);
1542 			return (-1);
1543 		}
1544 		(void) pclose(fp);
1545 
1546 		if ((lif->li_reconfig = strdup(buf)) == NULL) {
1547 			rcm_log_message(RCM_ERROR,
1548 			    _("IP: malloc error (%s) %s\n"),
1549 			    pif->pi_ifname, strerror(errno));
1550 			clr_cfg_state(pif);
1551 			return (-1);
1552 		}
1553 		rcm_log_message(RCM_DEBUG,
1554 		    "IP: if_cfginfo: reconfig string(%s:%d) = %s\n",
1555 		    pif->pi_ifname, lif->li_ifnum, lif->li_reconfig);
1556 
1557 		lif = lif->li_next;
1558 	}
1559 
1560 	return (0);
1561 }
1562 
1563 /*
1564  * if_unplumb() - Unplumb the interface
1565  *		Save off the modlist, ifconfig options and unplumb.
1566  *		Fail, if an unknown module lives between IP and driver and
1567  *		force is not set
1568  *		Call with cache_lock held
1569  */
1570 static int
1571 if_unplumb(ip_cache_t *node)
1572 {
1573 	ip_lif_t *lif;
1574 	ip_pif_t *pif = node->ip_pif;
1575 	boolean_t ipv4 = B_FALSE;
1576 	boolean_t ipv6 = B_FALSE;
1577 
1578 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s)\n", node->ip_resource);
1579 
1580 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1581 		if (lif->li_ifflags & IFF_IPV4) {
1582 			ipv4 = B_TRUE;
1583 		} else if (lif->li_ifflags & IFF_IPV6) {
1584 			ipv6 = B_TRUE;
1585 		} else {
1586 			/* Unlikely case */
1587 			rcm_log_message(RCM_DEBUG,
1588 			    "IP: Unplumb ignored (%s:%d)\n",
1589 			    pif->pi_ifname, lif->li_ifnum);
1590 		}
1591 	}
1592 
1593 	if (ipv4 && !ifconfig(pif->pi_ifname, "inet", "unplumb", B_FALSE)) {
1594 		rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
1595 		    pif->pi_ifname, strerror(errno));
1596 		return (-1);
1597 	}
1598 
1599 	if (ipv6 && !ifconfig(pif->pi_ifname, "inet6", "unplumb", B_FALSE)) {
1600 		rcm_log_message(RCM_ERROR, _("IP: Cannot unplumb (%s) %s\n"),
1601 		    pif->pi_ifname, strerror(errno));
1602 		return (-1);
1603 	}
1604 
1605 	rcm_log_message(RCM_TRACE2, "IP: if_unplumb(%s) success\n",
1606 	    node->ip_resource);
1607 
1608 	return (0);
1609 }
1610 
1611 /*
1612  * if_replumb() - Undo previous unplumb i.e. plumb back the physical interface
1613  *		instances and the logical interfaces in order, restoring
1614  *		all ifconfig options
1615  *		Call with cache_lock held
1616  */
1617 static int
1618 if_replumb(ip_cache_t *node)
1619 {
1620 	ip_lif_t *lif;
1621 	ip_pif_t *pif;
1622 	int i;
1623 	boolean_t success, ipmp;
1624 	const char *fstr;
1625 	char lifname[LIFNAMSIZ];
1626 	char buf[MAX_RECONFIG_SIZE];
1627 	int max_lifnum = 0;
1628 
1629 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s)\n", node->ip_resource);
1630 
1631 	/*
1632 	 * Be extra careful about bringing up the interfaces in the
1633 	 * correct order:
1634 	 * - First plumb in the physical interface instances
1635 	 * - modinsert the necessary modules@pos
1636 	 * - Next, add the logical interfaces being careful about
1637 	 *   the order, (follow the cached interface number li_ifnum order)
1638 	 */
1639 
1640 	pif = node->ip_pif;
1641 	ipmp = (node->ip_pif->pi_grname[0] != '\0');
1642 
1643 	/*
1644 	 * Make a first pass to plumb in physical interfaces and get a count
1645 	 * of the max logical interfaces
1646 	 */
1647 	for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1648 		max_lifnum = MAX(lif->li_ifnum, max_lifnum);
1649 		if (lif->li_ifflags & IFF_IPV4) {
1650 			fstr = "inet";
1651 		} else if (lif->li_ifflags & IFF_IPV6) {
1652 			fstr = "inet6";
1653 		} else {
1654 			/* Unlikely case */
1655 			rcm_log_message(RCM_DEBUG,
1656 			    "IP: Re-plumb ignored (%s:%d)\n",
1657 			    pif->pi_ifname, lif->li_ifnum);
1658 			continue;
1659 		}
1660 
1661 		/* ignore logical interface instances */
1662 		if (lif->li_ifnum != 0)
1663 			continue;
1664 
1665 		if ((lif->li_ifflags & IFF_NOFAILOVER) || !ipmp) {
1666 			success = ifconfig("", "", lif->li_reconfig, B_FALSE);
1667 		} else {
1668 			(void) snprintf(buf, sizeof (buf), "plumb group %s",
1669 			    pif->pi_grname);
1670 			success = ifconfig(pif->pi_ifname, fstr, buf, B_FALSE);
1671 		}
1672 
1673 		if (!success) {
1674 			rcm_log_message(RCM_ERROR,
1675 			    _("IP: Cannot plumb (%s) %s\n"), pif->pi_ifname,
1676 			    strerror(errno));
1677 			return (-1);
1678 		}
1679 
1680 		/*
1681 		 * Restart DHCP if necessary.
1682 		 */
1683 		if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1684 		    !ifconfig(pif->pi_ifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1685 			rcm_log_message(RCM_ERROR, _("IP: Cannot start DHCP "
1686 			    "(%s) %s\n"), pif->pi_ifname, strerror(errno));
1687 			return (-1);
1688 		}
1689 
1690 		rcm_log_message(RCM_TRACE2,
1691 		    "IP: if_replumb: Modcnt = %d\n", lif->li_modcnt);
1692 		/* modinsert modules in order, ignore driver(last) */
1693 		for (i = 0; i < (lif->li_modcnt - 1); i++) {
1694 			rcm_log_message(RCM_TRACE2,
1695 			    "IP: modinsert: Pos = %d Mod = %s\n",
1696 			    i, lif->li_modules[i]);
1697 			if (modop(pif->pi_ifname, lif->li_modules[i], i,
1698 			    MOD_INSERT) == -1) {
1699 				rcm_log_message(RCM_ERROR,
1700 				    _("IP: modinsert error(%s)\n"),
1701 				    pif->pi_ifname);
1702 				return (-1);
1703 			}
1704 		}
1705 	}
1706 
1707 	/* Now, add all the logical interfaces in the correct order */
1708 	for (i = 1; i <= max_lifnum; i++) {
1709 		(void) snprintf(lifname, LIFNAMSIZ, "%s:%d", pif->pi_ifname, i);
1710 
1711 		/* reset lif through every iteration */
1712 		for (lif = pif->pi_lifs; lif != NULL; lif = lif->li_next) {
1713 			/*
1714 			 * Process entries in order.  If the interface is
1715 			 * using IPMP, only process test addresses.
1716 			 */
1717 			if (lif->li_ifnum != i ||
1718 			    (ipmp && !(lif->li_ifflags & IFF_NOFAILOVER)))
1719 				continue;
1720 
1721 			if (!ifconfig("", "", lif->li_reconfig, B_FALSE)) {
1722 				rcm_log_message(RCM_ERROR,
1723 				    _("IP: Cannot addif (%s) %s\n"), lifname,
1724 				    strerror(errno));
1725 				return (-1);
1726 			}
1727 
1728 			/*
1729 			 * Restart DHCP if necessary.
1730 			 */
1731 			if ((lif->li_ifflags & IFF_DHCPRUNNING) &&
1732 			    !ifconfig(lifname, fstr, CFG_DHCP_CMD, B_FALSE)) {
1733 				rcm_log_message(RCM_ERROR,
1734 				    _("IP: Cannot start DHCP (%s) %s\n"),
1735 				    lifname, strerror(errno));
1736 				return (-1);
1737 			}
1738 		}
1739 	}
1740 
1741 	rcm_log_message(RCM_TRACE2, "IP: if_replumb(%s) success \n",
1742 	    node->ip_resource);
1743 
1744 	return (0);
1745 }
1746 
1747 /*
1748  * clr_cfg_state() - Cleanup after errors in unplumb
1749  */
1750 static void
1751 clr_cfg_state(ip_pif_t *pif)
1752 {
1753 	ip_lif_t *lif;
1754 	int i;
1755 
1756 	lif = pif->pi_lifs;
1757 
1758 	while (lif != NULL) {
1759 		lif->li_modcnt = 0;
1760 		free(lif->li_reconfig);
1761 		lif->li_reconfig = NULL;
1762 		for (i = 0; i < IP_MAX_MODS; i++) {
1763 			free(lif->li_modules[i]);
1764 			lif->li_modules[i] = NULL;
1765 		}
1766 		lif = lif->li_next;
1767 	}
1768 }
1769 
1770 /*
1771  * Attempt to offline ip_cache_t `node'; returns an IPMP error code.
1772  */
1773 static int
1774 ip_ipmp_offline(ip_cache_t *node)
1775 {
1776 	int retval;
1777 	ipmp_handle_t handle;
1778 
1779 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_offline\n");
1780 
1781 	if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
1782 		rcm_log_message(RCM_ERROR,
1783 		    _("IP: cannot create ipmp handle: %s\n"),
1784 		    ipmp_errmsg(retval));
1785 		return (retval);
1786 	}
1787 
1788 	retval = ipmp_offline(handle, node->ip_pif->pi_ifname, node->ip_ifred);
1789 	if (retval != IPMP_SUCCESS) {
1790 		rcm_log_message(RCM_ERROR, _("IP: ipmp_offline error: %s\n"),
1791 		    ipmp_errmsg(retval));
1792 	} else {
1793 		rcm_log_message(RCM_TRACE1, "IP: ipmp_offline success\n");
1794 	}
1795 
1796 	ipmp_close(handle);
1797 	return (retval);
1798 }
1799 
1800 /*
1801  * Attempt to undo the offline ip_cache_t `node'; returns an IPMP error code.
1802  */
1803 static int
1804 ip_ipmp_undo_offline(ip_cache_t *node)
1805 {
1806 	int retval;
1807 	ipmp_handle_t handle;
1808 
1809 	rcm_log_message(RCM_TRACE1, "IP: ip_ipmp_undo_offline\n");
1810 
1811 	if ((retval = ipmp_open(&handle)) != IPMP_SUCCESS) {
1812 		rcm_log_message(RCM_ERROR,
1813 		    _("IP: cannot create ipmp handle: %s\n"),
1814 		    ipmp_errmsg(retval));
1815 		return (retval);
1816 	}
1817 
1818 	retval = ipmp_undo_offline(handle, node->ip_pif->pi_ifname);
1819 	if (retval != IPMP_SUCCESS) {
1820 		rcm_log_message(RCM_ERROR,
1821 		    _("IP: ipmp_undo_offline error: %s\n"),
1822 		    ipmp_errmsg(retval));
1823 	} else {
1824 		rcm_log_message(RCM_TRACE1, "IP: ipmp_undo_offline success\n");
1825 	}
1826 
1827 	ipmp_close(handle);
1828 	return (retval);
1829 }
1830 
1831 /*
1832  * get_link_resource() - Convert a link name (e.g., net0, hme1000) into a
1833  * dynamically allocated string containing the associated link resource
1834  * name ("SUNW_datalink/<linkid>").
1835  */
1836 static char *
1837 get_link_resource(const char *link)
1838 {
1839 	char		errmsg[DLADM_STRSIZE];
1840 	datalink_id_t	linkid;
1841 	uint32_t	flags;
1842 	char		*resource;
1843 	dladm_status_t	status;
1844 
1845 	status = dladm_name2info(dld_handle, link, &linkid, &flags, NULL, NULL);
1846 	if (status != DLADM_STATUS_OK)
1847 		goto fail;
1848 
1849 	if (!(flags & DLADM_OPT_ACTIVE)) {
1850 		status = DLADM_STATUS_FAILED;
1851 		goto fail;
1852 	}
1853 
1854 	resource = malloc(RCM_LINK_RESOURCE_MAX);
1855 	if (resource == NULL) {
1856 		rcm_log_message(RCM_ERROR, _("IP: malloc error(%s): %s\n"),
1857 		    strerror(errno), link);
1858 		return (NULL);
1859 	}
1860 
1861 	(void) snprintf(resource, RCM_LINK_RESOURCE_MAX, "%s/%u",
1862 	    RCM_LINK_PREFIX, linkid);
1863 
1864 	return (resource);
1865 
1866 fail:
1867 	rcm_log_message(RCM_ERROR,
1868 	    _("IP: get_link_resource for %s error(%s)\n"),
1869 	    link, dladm_status2str(status, errmsg));
1870 	return (NULL);
1871 }
1872 
1873 /*
1874  * modop() - Remove/insert a module
1875  */
1876 static int
1877 modop(char *name, char *arg, int pos, char op)
1878 {
1879 	char syscmd[LIFNAMSIZ+MAXPATHLEN];	/* must be big enough */
1880 
1881 	rcm_log_message(RCM_TRACE1, "IP: modop(%s)\n", name);
1882 
1883 	/* Nothing to do with "ip", "arp" */
1884 	if ((arg == NULL) || (strcmp(arg, "") == 0) ||
1885 	    STREQ(arg, IP_MOD_NAME) || STREQ(arg, ARP_MOD_NAME)) {
1886 		rcm_log_message(RCM_TRACE1, "IP: modop success\n");
1887 		return (0);
1888 	}
1889 
1890 	if (op == MOD_CHECK) {
1891 		/*
1892 		 * No known good modules (yet) apart from ip and arp
1893 		 * which are handled above
1894 		 */
1895 		return (-1);
1896 	}
1897 
1898 	if (op == MOD_REMOVE) {
1899 		(void) snprintf(syscmd, sizeof (syscmd),
1900 		    "%s %s modremove %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
1901 	} else if (op == MOD_INSERT) {
1902 		(void) snprintf(syscmd, sizeof (syscmd),
1903 		    "%s %s modinsert %s@%d\n", SBIN_IFCONFIG, name, arg, pos);
1904 	} else {
1905 		rcm_log_message(RCM_ERROR,
1906 		    _("IP: modop(%s): unknown operation\n"), name);
1907 		return (-1);
1908 	}
1909 
1910 	rcm_log_message(RCM_TRACE1, "IP: modop(%s): %s\n", name, syscmd);
1911 	if (rcm_exec_cmd(syscmd) == -1) {
1912 		rcm_log_message(RCM_ERROR,
1913 		    _("IP: modop(%s): %s\n"), name, strerror(errno));
1914 		return (-1);
1915 	}
1916 
1917 	rcm_log_message(RCM_TRACE1, "IP: modop success\n");
1918 	return (0);
1919 }
1920 
1921 /*
1922  * get_modlist() - return a list of pushed mid-stream modules
1923  *		 Required memory is malloced to construct the list,
1924  *		 Caller must free this memory list
1925  *		 Call with cache_lock held
1926  */
1927 static int
1928 get_modlist(char *name, ip_lif_t *lif)
1929 {
1930 	int mux_fd;
1931 	int muxid_fd;
1932 	int fd;
1933 	int i;
1934 	int num_mods;
1935 	struct lifreq lifr;
1936 	struct str_list strlist = { 0 };
1937 
1938 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s)\n", name);
1939 
1940 	(void) strlcpy(lifr.lifr_name, name, sizeof (lifr.lifr_name));
1941 	lifr.lifr_flags = lif->li_ifflags;
1942 	if (ip_domux2fd(&mux_fd, &muxid_fd, &fd, &lifr) < 0) {
1943 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd(%s)\n"), name);
1944 		return (-1);
1945 	}
1946 
1947 	if ((num_mods = ioctl(fd, I_LIST, NULL)) < 0) {
1948 		rcm_log_message(RCM_ERROR,
1949 		    _("IP: get_modlist(%s): I_LIST(%s) \n"),
1950 		    name, strerror(errno));
1951 		goto fail;
1952 	}
1953 
1954 	strlist.sl_nmods = num_mods;
1955 	strlist.sl_modlist = malloc(sizeof (struct str_mlist) * num_mods);
1956 	if (strlist.sl_modlist == NULL) {
1957 		rcm_log_message(RCM_ERROR, _("IP: get_modlist(%s): %s\n"),
1958 		    name, strerror(errno));
1959 		goto fail;
1960 	}
1961 
1962 	if (ioctl(fd, I_LIST, (caddr_t)&strlist) < 0) {
1963 		rcm_log_message(RCM_ERROR,
1964 		    _("IP: get_modlist(%s): I_LIST error: %s\n"),
1965 		    name, strerror(errno));
1966 		goto fail;
1967 	}
1968 
1969 	for (i = 0; i < strlist.sl_nmods; i++) {
1970 		lif->li_modules[i] = strdup(strlist.sl_modlist[i].l_name);
1971 		if (lif->li_modules[i] == NULL) {
1972 			rcm_log_message(RCM_ERROR,
1973 			    _("IP: get_modlist(%s): %s\n"),
1974 			    name, strerror(errno));
1975 			while (i > 0)
1976 				free(lif->li_modules[--i]);
1977 			goto fail;
1978 		}
1979 	}
1980 
1981 	lif->li_modcnt = strlist.sl_nmods;
1982 	free(strlist.sl_modlist);
1983 
1984 	rcm_log_message(RCM_TRACE1, "IP: getmodlist(%s) success\n", name);
1985 	return (ip_plink(mux_fd, muxid_fd, fd, &lifr));
1986 fail:
1987 	free(strlist.sl_modlist);
1988 	(void) ip_plink(mux_fd, muxid_fd, fd, &lifr);
1989 	return (-1);
1990 }
1991 
1992 /*
1993  * ip_domux2fd() - Helper function for mod*() functions
1994  *		 Stolen from ifconfig.c
1995  */
1996 static int
1997 ip_domux2fd(int *mux_fd, int *muxid_fdp, int *fd, struct lifreq *lifr)
1998 {
1999 	int muxid_fd;
2000 	char	*udp_dev_name;
2001 
2002 	if (lifr->lifr_flags & IFF_IPV6) {
2003 		udp_dev_name  = UDP6_DEV_NAME;
2004 	} else {
2005 		udp_dev_name  = UDP_DEV_NAME;
2006 	}
2007 
2008 	if ((muxid_fd = open(udp_dev_name, O_RDWR)) < 0) {
2009 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2010 		    udp_dev_name, strerror(errno));
2011 		return (-1);
2012 	}
2013 	if ((*mux_fd = open(udp_dev_name, O_RDWR)) < 0) {
2014 		rcm_log_message(RCM_ERROR, _("IP: ip_domux2fd: open(%s) %s\n"),
2015 		    udp_dev_name, strerror(errno));
2016 		(void) close(muxid_fd);
2017 		return (-1);
2018 	}
2019 	if (ioctl(muxid_fd, SIOCGLIFMUXID, (caddr_t)lifr) < 0) {
2020 		rcm_log_message(RCM_ERROR,
2021 		    _("IP: ip_domux2fd: SIOCGLIFMUXID(%s): %s\n"),
2022 		    udp_dev_name, strerror(errno));
2023 		(void) close(*mux_fd);
2024 		(void) close(muxid_fd);
2025 		return (-1);
2026 	}
2027 
2028 	rcm_log_message(RCM_TRACE2,
2029 	    "IP: ip_domux2fd: ARP_muxid %d IP_muxid %d\n",
2030 	    lifr->lifr_arp_muxid, lifr->lifr_ip_muxid);
2031 
2032 	if ((*fd = ioctl(*mux_fd, _I_MUXID2FD, lifr->lifr_ip_muxid)) < 0) {
2033 		rcm_log_message(RCM_ERROR,
2034 		    _("IP: ip_domux2fd: _I_MUXID2FD(%s): %s\n"),
2035 		    udp_dev_name, strerror(errno));
2036 		(void) close(*mux_fd);
2037 		(void) close(muxid_fd);
2038 		return (-1);
2039 	}
2040 	if (ioctl(*mux_fd, I_PUNLINK, lifr->lifr_ip_muxid) < 0) {
2041 		rcm_log_message(RCM_ERROR,
2042 		    _("IP: ip_domux2fd: I_PUNLINK(%s): %s\n"),
2043 		    udp_dev_name, strerror(errno));
2044 		(void) close(*mux_fd);
2045 		(void) close(muxid_fd);
2046 		return (-1);
2047 	}
2048 
2049 	/* Note: mux_fd and muxid_fd are closed in ip_plink below */
2050 	*muxid_fdp = muxid_fd;
2051 	return (0);
2052 }
2053 
2054 /*
2055  * ip_plink() - Helper function for mod*() functions.
2056  *	      Stolen from ifconfig.c
2057  */
2058 static int
2059 ip_plink(int mux_fd, int muxid_fd, int fd, struct lifreq *lifr)
2060 {
2061 	int mux_id;
2062 
2063 	if ((mux_id = ioctl(mux_fd, I_PLINK, fd)) < 0) {
2064 		rcm_log_message(RCM_ERROR, _("IP: ip_plink I_PLINK(%s): %s\n"),
2065 		    UDP_DEV_NAME, strerror(errno));
2066 		(void) close(mux_fd);
2067 		(void) close(muxid_fd);
2068 		(void) close(fd);
2069 		return (-1);
2070 	}
2071 
2072 	lifr->lifr_ip_muxid = mux_id;
2073 	if (ioctl(muxid_fd, SIOCSLIFMUXID, (caddr_t)lifr) < 0) {
2074 		rcm_log_message(RCM_ERROR,
2075 		    _("IP: ip_plink SIOCSLIFMUXID(%s): %s\n"),
2076 		    UDP_DEV_NAME, strerror(errno));
2077 		(void) close(mux_fd);
2078 		(void) close(muxid_fd);
2079 		(void) close(fd);
2080 		return (-1);
2081 	}
2082 
2083 	(void) close(mux_fd);
2084 	(void) close(muxid_fd);
2085 	(void) close(fd);
2086 	return (0);
2087 }
2088 
2089 /*
2090  * ip_onlinelist()
2091  *
2092  *	Notify online to IP address consumers.
2093  */
2094 /*ARGSUSED*/
2095 static int
2096 ip_onlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2097 		rcm_info_t **depend_info)
2098 {
2099 	char **addrlist;
2100 	int ret = RCM_SUCCESS;
2101 
2102 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist\n");
2103 
2104 	addrlist = ip_get_addrlist(node);
2105 	if (addrlist == NULL || addrlist[0] == NULL) {
2106 		rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist none\n");
2107 		ip_free_addrlist(addrlist);
2108 		return (ret);
2109 	}
2110 
2111 	ret = rcm_notify_online_list(hd, addrlist, 0, depend_info);
2112 
2113 	ip_free_addrlist(addrlist);
2114 	rcm_log_message(RCM_TRACE2, "IP: ip_onlinelist done\n");
2115 	return (ret);
2116 }
2117 
2118 /*
2119  * ip_offlinelist()
2120  *
2121  *	Offline IP address consumers.
2122  */
2123 /*ARGSUSED*/
2124 static int
2125 ip_offlinelist(rcm_handle_t *hd, ip_cache_t *node, char **errorp, uint_t flags,
2126 	rcm_info_t **depend_info)
2127 {
2128 	char **addrlist;
2129 	int ret = RCM_SUCCESS;
2130 
2131 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist\n");
2132 
2133 	addrlist = ip_get_addrlist(node);
2134 	if (addrlist == NULL || addrlist[0] == NULL) {
2135 		rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist none\n");
2136 		ip_free_addrlist(addrlist);
2137 		return (RCM_SUCCESS);
2138 	}
2139 
2140 	if ((ret = rcm_request_offline_list(hd, addrlist, flags, depend_info))
2141 	    != RCM_SUCCESS) {
2142 		if (ret == RCM_FAILURE)
2143 			(void) rcm_notify_online_list(hd, addrlist, 0, NULL);
2144 
2145 		ret = RCM_FAILURE;
2146 	}
2147 
2148 	ip_free_addrlist(addrlist);
2149 	rcm_log_message(RCM_TRACE2, "IP: ip_offlinelist done\n");
2150 	return (ret);
2151 }
2152 
2153 /*
2154  * ip_get_addrlist() -	Get the list of IP addresses on this interface (node);
2155  *			This routine malloc()s required memory for the list.
2156  *			Returns the list on success, NULL on failure.
2157  *			Call with cache_lock held.
2158  */
2159 static char **
2160 ip_get_addrlist(ip_cache_t *node)
2161 {
2162 	ip_lif_t *lif;
2163 	char **addrlist = NULL;
2164 	int i, numifs;
2165 	size_t addrlistsize;
2166 	char addrstr[INET6_ADDRSTRLEN];
2167 
2168 	rcm_log_message(RCM_TRACE2, "IP: ip_get_addrlist(%s)\n",
2169 	    node->ip_resource);
2170 
2171 	numifs = 0;
2172 	for (lif = node->ip_pif->pi_lifs; lif != NULL; lif = lif->li_next) {
2173 		numifs++;
2174 	}
2175 
2176 	/*
2177 	 * Allocate space for resource names list; add 1 and use calloc()
2178 	 * so that the list is NULL-terminated.
2179 	 */
2180 	if ((addrlist = calloc(numifs + 1, sizeof (char *))) == NULL) {
2181 		rcm_log_message(RCM_ERROR,
2182 		    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2183 		    node->ip_resource, strerror(errno));
2184 		return (NULL);
2185 	}
2186 
2187 	for (lif = node->ip_pif->pi_lifs, i = 0; lif != NULL;
2188 	    lif = lif->li_next, i++) {
2189 
2190 		if (!ip_addrstr(lif, addrstr, sizeof (addrstr))) {
2191 			ip_free_addrlist(addrlist);
2192 			return (NULL);
2193 		}
2194 
2195 		addrlistsize = strlen(addrstr) + sizeof (RCM_STR_SUNW_IP);
2196 		if ((addrlist[i] = malloc(addrlistsize)) == NULL) {
2197 			rcm_log_message(RCM_ERROR,
2198 			    _("IP: ip_get_addrlist(%s) malloc failure(%s)\n"),
2199 			    node->ip_resource, strerror(errno));
2200 			ip_free_addrlist(addrlist);
2201 			return (NULL);
2202 		}
2203 		(void) snprintf(addrlist[i], addrlistsize, "%s%s",
2204 		    RCM_STR_SUNW_IP, addrstr);
2205 
2206 		rcm_log_message(RCM_DEBUG, "Anon Address: %s\n", addrlist[i]);
2207 	}
2208 
2209 	rcm_log_message(RCM_TRACE2, "IP: get_addrlist (%s) done\n",
2210 	    node->ip_resource);
2211 
2212 	return (addrlist);
2213 }
2214 
2215 static void
2216 ip_free_addrlist(char **addrlist)
2217 {
2218 	int i;
2219 
2220 	if (addrlist == NULL)
2221 		return;
2222 
2223 	for (i = 0; addrlist[i] != NULL; i++)
2224 		free(addrlist[i]);
2225 	free(addrlist);
2226 }
2227 
2228 /*
2229  * ip_consumer_notify() - Notify consumers of IP addresses coming back online.
2230  */
2231 
2232 static void
2233 ip_consumer_notify(rcm_handle_t *hd, datalink_id_t linkid, char **errorp,
2234     uint_t flags, rcm_info_t **depend_info)
2235 {
2236 	char cached_name[RCM_LINK_RESOURCE_MAX];
2237 	ip_cache_t *node;
2238 
2239 	assert(linkid != DATALINK_INVALID_LINKID);
2240 
2241 	rcm_log_message(RCM_TRACE1, _("IP: ip_consumer_notify(%u)\n"), linkid);
2242 
2243 	/* Check for the interface in the cache */
2244 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2245 	    RCM_LINK_PREFIX, linkid);
2246 
2247 	(void) mutex_lock(&cache_lock);
2248 	if ((node = cache_lookup(hd, cached_name, CACHE_REFRESH)) == NULL) {
2249 		rcm_log_message(RCM_TRACE1, _("IP: Skipping interface(%u)\n"),
2250 		    linkid);
2251 		(void) mutex_unlock(&cache_lock);
2252 		return;
2253 	}
2254 	/*
2255 	 * Inform anonymous consumers about IP addresses being onlined.
2256 	 */
2257 	(void) ip_onlinelist(hd, node, errorp, flags, depend_info);
2258 
2259 	(void) mutex_unlock(&cache_lock);
2260 
2261 	rcm_log_message(RCM_TRACE2, "IP: ip_consumer_notify success\n");
2262 }
2263 
2264 /*
2265  * if_configure() - Configure a physical interface after attach
2266  */
2267 static int
2268 if_configure(datalink_id_t linkid)
2269 {
2270 	char ifinst[MAXLINKNAMELEN];
2271 	char cfgfile[MAXPATHLEN];
2272 	char cached_name[RCM_LINK_RESOURCE_MAX];
2273 	FILE *hostfp, *host6fp;
2274 	ip_cache_t *node;
2275 	boolean_t ipmp = B_FALSE;
2276 
2277 	assert(linkid != DATALINK_INVALID_LINKID);
2278 	rcm_log_message(RCM_TRACE1, _("IP: if_configure(%u)\n"), linkid);
2279 
2280 	/* Check for the interface in the cache */
2281 	(void) snprintf(cached_name, sizeof (cached_name), "%s/%u",
2282 	    RCM_LINK_PREFIX, linkid);
2283 
2284 	/* Check if the interface is new or was not previously offlined */
2285 	(void) mutex_lock(&cache_lock);
2286 	if (((node = cache_lookup(NULL, cached_name, CACHE_REFRESH)) != NULL) &&
2287 	    (!(node->ip_cachestate & CACHE_IF_OFFLINED))) {
2288 		rcm_log_message(RCM_TRACE1,
2289 		    _("IP: Skipping configured interface(%u)\n"), linkid);
2290 		(void) mutex_unlock(&cache_lock);
2291 		return (0);
2292 	}
2293 	(void) mutex_unlock(&cache_lock);
2294 
2295 	if (dladm_datalink_id2info(dld_handle, linkid, NULL, NULL, NULL, ifinst,
2296 	    sizeof (ifinst)) != DLADM_STATUS_OK) {
2297 		rcm_log_message(RCM_ERROR,
2298 		    _("IP: get %u link name failed\n"), linkid);
2299 		return (-1);
2300 	}
2301 
2302 	/*
2303 	 * Scan the IPv4 and IPv6 hostname files to see if (a) they exist
2304 	 * and (b) if either one places the interface into an IPMP group.
2305 	 */
2306 	(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV4, ifinst);
2307 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2308 	if ((hostfp = fopen(cfgfile, "r")) != NULL) {
2309 		if (isgrouped(cfgfile))
2310 			ipmp = B_TRUE;
2311 	}
2312 
2313 	(void) snprintf(cfgfile, MAXPATHLEN, CFGFILE_FMT_IPV6, ifinst);
2314 	rcm_log_message(RCM_TRACE1, "IP: Scanning %s\n", cfgfile);
2315 	if ((host6fp = fopen(cfgfile, "r")) != NULL) {
2316 		if (!ipmp && isgrouped(cfgfile))
2317 			ipmp = B_TRUE;
2318 	}
2319 
2320 	/*
2321 	 * Configure the interface according to its hostname files.
2322 	 */
2323 	if (hostfp != NULL &&
2324 	    if_config_inst(ifinst, hostfp, AF_INET, ipmp) == -1) {
2325 		rcm_log_message(RCM_ERROR,
2326 		    _("IP: IPv4 Post-attach failed (%s)\n"), ifinst);
2327 		goto fail;
2328 	}
2329 
2330 	if (host6fp != NULL &&
2331 	    if_config_inst(ifinst, host6fp, AF_INET6, ipmp) == -1) {
2332 		rcm_log_message(RCM_ERROR,
2333 		    _("IP: IPv6 Post-attach failed (%s)\n"), ifinst);
2334 		goto fail;
2335 	}
2336 
2337 	(void) fclose(hostfp);
2338 	(void) fclose(host6fp);
2339 	rcm_log_message(RCM_TRACE1, "IP: if_configure(%s) success\n", ifinst);
2340 	return (0);
2341 fail:
2342 	(void) fclose(hostfp);
2343 	(void) fclose(host6fp);
2344 	return (-1);
2345 }
2346 
2347 /*
2348  * isgrouped() - Scans the given config file to see if this interface is
2349  *	         using IPMP.  Returns B_TRUE or B_FALSE.
2350  */
2351 static boolean_t
2352 isgrouped(const char *cfgfile)
2353 {
2354 	FILE *fp;
2355 	struct stat statb;
2356 	char *nlp, *line, *token, *lasts, *buf;
2357 	boolean_t grouped = B_FALSE;
2358 
2359 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s)\n", cfgfile);
2360 
2361 	if (stat(cfgfile, &statb) != 0) {
2362 		rcm_log_message(RCM_TRACE1,
2363 		    _("IP: No config file(%s)\n"), cfgfile);
2364 		return (B_FALSE);
2365 	}
2366 
2367 	/*
2368 	 * We also ignore single-byte config files because the file should
2369 	 * always be newline-terminated, so we know there's nothing of
2370 	 * interest.  Further, a single-byte file would cause the fgets() loop
2371 	 * below to spin forever.
2372 	 */
2373 	if (statb.st_size <= 1) {
2374 		rcm_log_message(RCM_TRACE1,
2375 		    _("IP: Empty config file(%s)\n"), cfgfile);
2376 		return (B_FALSE);
2377 	}
2378 
2379 	if ((fp = fopen(cfgfile, "r")) == NULL) {
2380 		rcm_log_message(RCM_ERROR,
2381 		    _("IP: Cannot open configuration file(%s): %s\n"), cfgfile,
2382 		    strerror(errno));
2383 		return (B_FALSE);
2384 	}
2385 
2386 	if ((buf = malloc(statb.st_size)) == NULL) {
2387 		rcm_log_message(RCM_ERROR,
2388 		    _("IP: malloc failure(%s): %s\n"), cfgfile,
2389 		    strerror(errno));
2390 		goto out;
2391 	}
2392 
2393 	while (fgets(buf, statb.st_size, fp) != NULL) {
2394 		if ((nlp = strrchr(buf, '\n')) != NULL)
2395 			*nlp = '\0';
2396 
2397 		line = buf;
2398 		while ((token = strtok_r(line, " \t", &lasts)) != NULL) {
2399 			line = NULL;
2400 			if (STREQ("group", token) &&
2401 			    strtok_r(NULL, " \t", &lasts) != NULL) {
2402 				grouped = B_TRUE;
2403 				goto out;
2404 			}
2405 		}
2406 	}
2407 out:
2408 	free(buf);
2409 	(void) fclose(fp);
2410 
2411 	rcm_log_message(RCM_TRACE1, "IP: isgrouped(%s): %d\n", cfgfile,
2412 	    grouped);
2413 
2414 	return (grouped);
2415 }
2416 
2417 /*
2418  * if_config_inst() - Configure an interface instance as specified by the
2419  *		    address family af and if it is grouped (ipmp).
2420  */
2421 static int
2422 if_config_inst(const char *ifinst, FILE *hfp, int af, boolean_t ipmp)
2423 {
2424 	FILE *ifparsefp;
2425 	struct stat statb;
2426 	char *buf = NULL;
2427 	char *ifparsebuf = NULL;
2428 	uint_t ifparsebufsize;
2429 	const char *fstr;		/* address family string */
2430 	boolean_t stdif = B_FALSE;
2431 
2432 	rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) ipmp = %d\n",
2433 	    ifinst, ipmp);
2434 
2435 	if (fstat(fileno(hfp), &statb) != 0) {
2436 		rcm_log_message(RCM_ERROR,
2437 		    _("IP: Cannot fstat file(%s)\n"), ifinst);
2438 		goto fail;
2439 	}
2440 
2441 	switch (af) {
2442 	case AF_INET:
2443 		fstr = "inet";
2444 		break;
2445 	case AF_INET6:
2446 		fstr = "inet6";
2447 		break;
2448 	default:
2449 		assert(0);
2450 	}
2451 
2452 	/*
2453 	 * The hostname file exists; plumb the physical interface.
2454 	 */
2455 	if (!ifconfig(ifinst, fstr, "plumb", B_FALSE))
2456 		goto fail;
2457 
2458 	/* Skip static configuration if the hostname file is empty */
2459 	if (statb.st_size <= 1) {
2460 		rcm_log_message(RCM_TRACE1,
2461 		    _("IP: Zero size hostname file(%s)\n"), ifinst);
2462 		goto configured;
2463 	}
2464 
2465 	if (fseek(hfp, 0, SEEK_SET) == -1) {
2466 		rcm_log_message(RCM_ERROR,
2467 		    _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2468 		    strerror(errno));
2469 		goto fail;
2470 	}
2471 
2472 	/*
2473 	 * Allocate the worst-case single-line buffer sizes.  A bit skanky,
2474 	 * but since hostname files are small, this should suffice.
2475 	 */
2476 	if ((buf = calloc(1, statb.st_size)) == NULL) {
2477 		rcm_log_message(RCM_ERROR,
2478 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2479 		goto fail;
2480 	}
2481 
2482 	ifparsebufsize = statb.st_size + sizeof (SBIN_IFPARSE " -s inet6 ");
2483 	if ((ifparsebuf = calloc(1, ifparsebufsize)) == NULL) {
2484 		rcm_log_message(RCM_ERROR,
2485 		    _("IP: calloc(%s): %s\n"), ifinst, strerror(errno));
2486 		goto fail;
2487 	}
2488 
2489 	/*
2490 	 * For IPv4, determine whether the hostname file consists of a single
2491 	 * line.  We need to handle these specially since they should
2492 	 * automatically be suffixed with "netmask + broadcast + up".
2493 	 */
2494 	if (af == AF_INET &&
2495 	    fgets(buf, statb.st_size, hfp) != NULL &&
2496 	    fgets(buf, statb.st_size, hfp) == NULL) {
2497 		rcm_log_message(RCM_TRACE1, "IP: one-line hostname file\n");
2498 		stdif = B_TRUE;
2499 	}
2500 
2501 	if (fseek(hfp, 0L, SEEK_SET) == -1) {
2502 		rcm_log_message(RCM_ERROR,
2503 		    _("IP: Cannot rewind hostname file(%s): %s\n"), ifinst,
2504 		    strerror(errno));
2505 		goto fail;
2506 	}
2507 
2508 	/*
2509 	 * Loop through the file one line at a time and feed it to ifconfig.
2510 	 * If the interface is using IPMP, then we use /sbin/ifparse -s to
2511 	 * weed out all of the data addresses, since those are already on the
2512 	 * IPMP meta-interface.
2513 	 */
2514 	while (fgets(buf, statb.st_size, hfp) != NULL) {
2515 		if (ntok(buf) == 0)
2516 			continue;
2517 
2518 		if (!ipmp) {
2519 			(void) ifconfig(ifinst, fstr, buf, stdif);
2520 			continue;
2521 		}
2522 
2523 		(void) snprintf(ifparsebuf, ifparsebufsize, SBIN_IFPARSE
2524 		    " -s %s %s", fstr, buf);
2525 		if ((ifparsefp = popen(ifparsebuf, "r")) == NULL) {
2526 			rcm_log_message(RCM_ERROR,
2527 			    _("IP: cannot configure %s: popen \"%s\" "
2528 			    "failed: %s\n"), ifinst, buf, strerror(errno));
2529 			goto fail;
2530 		}
2531 
2532 		while (fgets(buf, statb.st_size, ifparsefp) != NULL) {
2533 			if (ntok(buf) > 0)
2534 				(void) ifconfig(ifinst, fstr, buf, stdif);
2535 		}
2536 
2537 		if (pclose(ifparsefp) == -1) {
2538 			rcm_log_message(RCM_ERROR,
2539 			    _("IP: cannot configure %s: pclose \"%s\" "
2540 			    "failed: %s\n"), ifinst, buf, strerror(errno));
2541 			goto fail;
2542 		}
2543 	}
2544 
2545 configured:
2546 	/*
2547 	 * Bring up the interface (it may already be up)
2548 	 *
2549 	 * Technically, since the boot scripts only unconditionally bring up
2550 	 * IPv6 interfaces, we should only unconditionally bring up IPv6 here.
2551 	 * However, if we don't bring up IPv4, and a legacy IPMP configuration
2552 	 * without test addresses is being used, we will never bring the
2553 	 * interface up even though we would've at boot.  One fix is to check
2554 	 * if the IPv4 hostname file contains data addresses that we would've
2555 	 * brought up, but there's no simple way to do that.  Given that it's
2556 	 * rare to have persistent IP configuration for an interface that
2557 	 * leaves it down, we cheap out and always bring it up for IPMP.
2558 	 */
2559 	if ((af == AF_INET6 || ipmp) && !ifconfig(ifinst, fstr, "up", B_FALSE))
2560 		goto fail;
2561 
2562 	/*
2563 	 * For IPv4, if a DHCP configuration file exists, have DHCP configure
2564 	 * the interface.  As with the boot scripts, this is done after the
2565 	 * hostname files are processed so that configuration in those files
2566 	 * (such as IPMP group names) will be applied first.
2567 	 */
2568 	if (af == AF_INET) {
2569 		char dhcpfile[MAXPATHLEN];
2570 		char *dhcpbuf;
2571 		off_t i, dhcpsize;
2572 
2573 		(void) snprintf(dhcpfile, MAXPATHLEN, DHCPFILE_FMT, ifinst);
2574 		if (stat(dhcpfile, &statb) == -1)
2575 			goto out;
2576 
2577 		if ((dhcpbuf = copylist(dhcpfile, &dhcpsize)) == NULL) {
2578 			rcm_log_message(RCM_ERROR, _("IP: cannot read "
2579 			    "(%s): %s\n"), dhcpfile, strerror(errno));
2580 			goto fail;
2581 		}
2582 
2583 		/*
2584 		 * The copylist() API converts \n's to \0's, but we want them
2585 		 * to be spaces.
2586 		 */
2587 		if (dhcpsize > 0) {
2588 			for (i = 0; i < dhcpsize; i++)
2589 				if (dhcpbuf[i] == '\0')
2590 					dhcpbuf[i] = ' ';
2591 			dhcpbuf[dhcpsize - 1] = '\0';
2592 		}
2593 		(void) ifconfig(ifinst, CFG_DHCP_CMD, dhcpbuf, B_FALSE);
2594 		free(dhcpbuf);
2595 	}
2596 out:
2597 	free(ifparsebuf);
2598 	free(buf);
2599 	rcm_log_message(RCM_TRACE1, "IP: if_config_inst(%s) success\n", ifinst);
2600 	return (0);
2601 fail:
2602 	free(ifparsebuf);
2603 	free(buf);
2604 	rcm_log_message(RCM_ERROR, "IP: if_config_inst(%s) failure\n", ifinst);
2605 	return (-1);
2606 }
2607 
2608 /*
2609  * ntok() - count the number of tokens in the provided buffer.
2610  */
2611 static uint_t
2612 ntok(const char *cp)
2613 {
2614 	uint_t ntok = 0;
2615 
2616 	for (;;) {
2617 		while (ISSPACE(*cp))
2618 			cp++;
2619 
2620 		if (ISEOL(*cp))
2621 			break;
2622 
2623 		do {
2624 			cp++;
2625 		} while (!ISSPACE(*cp) && !ISEOL(*cp));
2626 
2627 		ntok++;
2628 	}
2629 	return (ntok);
2630 }
2631 
2632 static boolean_t
2633 ifconfig(const char *ifinst, const char *fstr, const char *buf, boolean_t stdif)
2634 {
2635 	char syscmd[MAX_RECONFIG_SIZE + MAXPATHLEN + 1];
2636 	int status;
2637 
2638 	(void) snprintf(syscmd, sizeof (syscmd), SBIN_IFCONFIG " %s %s %s",
2639 	    ifinst, fstr, buf);
2640 
2641 	if (stdif)
2642 		(void) strlcat(syscmd, CFG_CMDS_STD, sizeof (syscmd));
2643 
2644 	rcm_log_message(RCM_TRACE1, "IP: Exec: %s\n", syscmd);
2645 	if ((status = rcm_exec_cmd(syscmd)) != 0) {
2646 		if (WIFEXITED(status)) {
2647 			rcm_log_message(RCM_ERROR, _("IP: \"%s\" failed with "
2648 			    "exit status %d\n"), syscmd, WEXITSTATUS(status));
2649 		} else {
2650 			rcm_log_message(RCM_ERROR, _("IP: Error: %s: %s\n"),
2651 			    syscmd, strerror(errno));
2652 		}
2653 		return (B_FALSE);
2654 	}
2655 	return (B_TRUE);
2656 }
2657