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