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