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