17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5ba2e4443Sseb  * Common Development and Distribution License (the "License").
6ba2e4443Sseb  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22d4d1f7bfSVasumathi Sundaram - Sun Microsystems  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * This RCM module adds support to the RCM framework for an abstract
287c478bd9Sstevel@tonic-gate  * namespace for network devices (DLPI providers).
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate #include <alloca.h>
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate #include <assert.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <synch.h>
377c478bd9Sstevel@tonic-gate #include <libintl.h>
387c478bd9Sstevel@tonic-gate #include <errno.h>
397c478bd9Sstevel@tonic-gate #include <libdevinfo.h>
407c478bd9Sstevel@tonic-gate #include <sys/types.h>
41210db224Sericheng #include <net/if.h>
42d62bc4baSyz #include <libdllink.h>
437c478bd9Sstevel@tonic-gate #include "rcm_module.h"
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate /*
467c478bd9Sstevel@tonic-gate  * Definitions
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate #ifndef	lint
497c478bd9Sstevel@tonic-gate #define	_(x)	gettext(x)
507c478bd9Sstevel@tonic-gate #else
517c478bd9Sstevel@tonic-gate #define	_(x)	x
527c478bd9Sstevel@tonic-gate #endif
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #define	CACHE_STALE	1	/* flags */
557c478bd9Sstevel@tonic-gate #define	CACHE_NEW	2	/* flags */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /* operations */
587c478bd9Sstevel@tonic-gate #define	NET_OFFLINE	1
597c478bd9Sstevel@tonic-gate #define	NET_ONLINE	2
607c478bd9Sstevel@tonic-gate #define	NET_REMOVE	3
617c478bd9Sstevel@tonic-gate #define	NET_SUSPEND	4
627c478bd9Sstevel@tonic-gate #define	NET_RESUME	5
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate typedef struct net_cache
657c478bd9Sstevel@tonic-gate {
667c478bd9Sstevel@tonic-gate 	char			*resource;
67d62bc4baSyz 	datalink_id_t		linkid;
687c478bd9Sstevel@tonic-gate 	int			flags;
697c478bd9Sstevel@tonic-gate 	struct net_cache	*next;
707c478bd9Sstevel@tonic-gate 	struct net_cache	*prev;
717c478bd9Sstevel@tonic-gate } net_cache_t;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static net_cache_t	cache_head;
747c478bd9Sstevel@tonic-gate static net_cache_t	cache_tail;
757c478bd9Sstevel@tonic-gate static mutex_t		cache_lock;
76d62bc4baSyz static int		events_registered = 0;
77d62bc4baSyz 
784ac67f02SAnurag S. Maskey static dladm_handle_t	dld_handle = NULL;
794ac67f02SAnurag S. Maskey 
807c478bd9Sstevel@tonic-gate /* module interface routines */
817c478bd9Sstevel@tonic-gate static int net_register(rcm_handle_t *);
827c478bd9Sstevel@tonic-gate static int net_unregister(rcm_handle_t *);
837c478bd9Sstevel@tonic-gate static int net_getinfo(rcm_handle_t *, char *, id_t, uint_t, char **,
847c478bd9Sstevel@tonic-gate     char **, nvlist_t *, rcm_info_t **);
857c478bd9Sstevel@tonic-gate static int net_suspend(rcm_handle_t *, char *, id_t, timespec_t *,
867c478bd9Sstevel@tonic-gate     uint_t, char **, rcm_info_t **);
877c478bd9Sstevel@tonic-gate static int net_resume(rcm_handle_t *, char *, id_t, uint_t, char **,
887c478bd9Sstevel@tonic-gate     rcm_info_t **);
897c478bd9Sstevel@tonic-gate static int net_offline(rcm_handle_t *, char *, id_t, uint_t, char **,
907c478bd9Sstevel@tonic-gate     rcm_info_t **);
917c478bd9Sstevel@tonic-gate static int net_online(rcm_handle_t *, char *, id_t, uint_t, char **,
927c478bd9Sstevel@tonic-gate     rcm_info_t **);
937c478bd9Sstevel@tonic-gate static int net_remove(rcm_handle_t *, char *, id_t, uint_t, char **,
947c478bd9Sstevel@tonic-gate     rcm_info_t **);
95d62bc4baSyz static int net_notify_event(rcm_handle_t *, char *, id_t, uint_t,
96d62bc4baSyz     char **, nvlist_t *, rcm_info_t **);
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /* module private routines */
997c478bd9Sstevel@tonic-gate static void free_cache(void);
1007c478bd9Sstevel@tonic-gate static void update_cache(rcm_handle_t *hd);
1017c478bd9Sstevel@tonic-gate static int devfs_entry(di_node_t node, di_minor_t minor, void *arg);
1027c478bd9Sstevel@tonic-gate static void cache_remove(net_cache_t *node);
1037c478bd9Sstevel@tonic-gate static net_cache_t *cache_lookup(const char *resource);
1047c478bd9Sstevel@tonic-gate static void free_node(net_cache_t *);
1057c478bd9Sstevel@tonic-gate static void cache_insert(net_cache_t *);
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * Module-Private data
1097c478bd9Sstevel@tonic-gate  */
1107c478bd9Sstevel@tonic-gate static struct rcm_mod_ops net_ops = {
1117c478bd9Sstevel@tonic-gate 	RCM_MOD_OPS_VERSION,
1127c478bd9Sstevel@tonic-gate 	net_register,
1137c478bd9Sstevel@tonic-gate 	net_unregister,
1147c478bd9Sstevel@tonic-gate 	net_getinfo,
1157c478bd9Sstevel@tonic-gate 	net_suspend,
1167c478bd9Sstevel@tonic-gate 	net_resume,
1177c478bd9Sstevel@tonic-gate 	net_offline,
1187c478bd9Sstevel@tonic-gate 	net_online,
119d62bc4baSyz 	net_remove,
120d62bc4baSyz 	NULL,
121d62bc4baSyz 	NULL,
122d62bc4baSyz 	net_notify_event
1237c478bd9Sstevel@tonic-gate };
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate /*
1267c478bd9Sstevel@tonic-gate  * Module Interface Routines
1277c478bd9Sstevel@tonic-gate  */
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate  * rcm_mod_init()
1317c478bd9Sstevel@tonic-gate  *
1327c478bd9Sstevel@tonic-gate  *	Update registrations, and return the ops structure.
1337c478bd9Sstevel@tonic-gate  */
1347c478bd9Sstevel@tonic-gate struct rcm_mod_ops *
rcm_mod_init(void)1357c478bd9Sstevel@tonic-gate rcm_mod_init(void)
1367c478bd9Sstevel@tonic-gate {
137d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	dladm_status_t	status;
138d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	char		errmsg[DLADM_STRSIZE];
139d4d1f7bfSVasumathi Sundaram - Sun Microsystems 
1407c478bd9Sstevel@tonic-gate 	cache_head.next = &cache_tail;
1417c478bd9Sstevel@tonic-gate 	cache_head.prev = NULL;
1427c478bd9Sstevel@tonic-gate 	cache_tail.prev = &cache_head;
1437c478bd9Sstevel@tonic-gate 	cache_tail.next = NULL;
144*46fbc806SToomas Soome 	(void) mutex_init(&cache_lock, USYNC_THREAD, NULL);
1457c478bd9Sstevel@tonic-gate 
146d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	if ((status = dladm_open(&dld_handle)) != DLADM_STATUS_OK) {
147d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		rcm_log_message(RCM_WARNING,
148d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		    "NET: mod_init failed: cannot open datalink handle: %s\n",
149d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		    dladm_status2str(status, errmsg));
150d4d1f7bfSVasumathi Sundaram - Sun Microsystems 		return (NULL);
151d4d1f7bfSVasumathi Sundaram - Sun Microsystems 	}
1524ac67f02SAnurag S. Maskey 
1537c478bd9Sstevel@tonic-gate 	/* Return the ops vectors */
1547c478bd9Sstevel@tonic-gate 	return (&net_ops);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate /*
1587c478bd9Sstevel@tonic-gate  * rcm_mod_info()
1597c478bd9Sstevel@tonic-gate  *
1607c478bd9Sstevel@tonic-gate  *	Return a string describing this module.
1617c478bd9Sstevel@tonic-gate  */
1627c478bd9Sstevel@tonic-gate const char *
rcm_mod_info(void)1637c478bd9Sstevel@tonic-gate rcm_mod_info(void)
1647c478bd9Sstevel@tonic-gate {
165648495d6Svikram 	return ("Network namespace module 1.13");
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate  * rcm_mod_fini()
1707c478bd9Sstevel@tonic-gate  *
1717c478bd9Sstevel@tonic-gate  *	Destroy the cache.
1727c478bd9Sstevel@tonic-gate  */
1737c478bd9Sstevel@tonic-gate int
rcm_mod_fini(void)1747c478bd9Sstevel@tonic-gate rcm_mod_fini(void)
1757c478bd9Sstevel@tonic-gate {
1767c478bd9Sstevel@tonic-gate 	free_cache();
1777c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&cache_lock);
1784ac67f02SAnurag S. Maskey 
1794ac67f02SAnurag S. Maskey 	dladm_close(dld_handle);
1807c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate  * net_register()
1857c478bd9Sstevel@tonic-gate  *
1867c478bd9Sstevel@tonic-gate  *	Make sure the cache is properly sync'ed, and its registrations
1877c478bd9Sstevel@tonic-gate  *	are in order.
1887c478bd9Sstevel@tonic-gate  *
1897c478bd9Sstevel@tonic-gate  *	Locking: the cache is locked by update_cache, and is held
1907c478bd9Sstevel@tonic-gate  *	throughout update_cache's execution because it reads and
1917c478bd9Sstevel@tonic-gate  *	possibly modifies cache links continuously.
1927c478bd9Sstevel@tonic-gate  */
1937c478bd9Sstevel@tonic-gate static int
net_register(rcm_handle_t * hd)1947c478bd9Sstevel@tonic-gate net_register(rcm_handle_t *hd)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	update_cache(hd);
197d62bc4baSyz 	/*
198d62bc4baSyz 	 * Need to register interest in all new resources
199d62bc4baSyz 	 * getting attached, so we get attach event notifications
200d62bc4baSyz 	 */
201d62bc4baSyz 	if (!events_registered) {
2025093e103SCathy Zhou 		if (rcm_register_event(hd, RCM_RESOURCE_PHYSLINK_NEW, 0, NULL)
203d62bc4baSyz 		    != RCM_SUCCESS) {
204d62bc4baSyz 			rcm_log_message(RCM_ERROR,
205d62bc4baSyz 			    _("NET: failed to register %s\n"),
2065093e103SCathy Zhou 			    RCM_RESOURCE_PHYSLINK_NEW);
207d62bc4baSyz 			return (RCM_FAILURE);
208d62bc4baSyz 		} else {
2095093e103SCathy Zhou 			rcm_log_message(RCM_DEBUG, _("NET: registered %s \n"),
2105093e103SCathy Zhou 			    RCM_RESOURCE_PHYSLINK_NEW);
211d62bc4baSyz 			events_registered++;
212d62bc4baSyz 		}
213d62bc4baSyz 	}
214d62bc4baSyz 
2157c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * net_unregister()
2207c478bd9Sstevel@tonic-gate  *
2217c478bd9Sstevel@tonic-gate  *	Manually walk through the cache, unregistering all the networks.
2227c478bd9Sstevel@tonic-gate  *
2237c478bd9Sstevel@tonic-gate  *	Locking: the cache is locked throughout the execution of this routine
2247c478bd9Sstevel@tonic-gate  *	because it reads and modifies cache links continuously.
2257c478bd9Sstevel@tonic-gate  */
2267c478bd9Sstevel@tonic-gate static int
net_unregister(rcm_handle_t * hd)2277c478bd9Sstevel@tonic-gate net_unregister(rcm_handle_t *hd)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate 	net_cache_t *probe;
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 	/* Walk the cache, unregistering everything */
2347c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
2357c478bd9Sstevel@tonic-gate 	probe = cache_head.next;
2367c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
2377c478bd9Sstevel@tonic-gate 		(void) rcm_unregister_interest(hd, probe->resource, 0);
2387c478bd9Sstevel@tonic-gate 		cache_remove(probe);
2397c478bd9Sstevel@tonic-gate 		free_node(probe);
2407c478bd9Sstevel@tonic-gate 		probe = cache_head.next;
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
243d62bc4baSyz 
244d62bc4baSyz 	/*
245d62bc4baSyz 	 * Need to unregister interest in all new resources
246d62bc4baSyz 	 */
247d62bc4baSyz 	if (events_registered) {
2485093e103SCathy Zhou 		if (rcm_unregister_event(hd, RCM_RESOURCE_PHYSLINK_NEW, 0)
249d62bc4baSyz 		    != RCM_SUCCESS) {
250d62bc4baSyz 			rcm_log_message(RCM_ERROR,
251d62bc4baSyz 			    _("NET: failed to unregister %s\n"),
2525093e103SCathy Zhou 			    RCM_RESOURCE_PHYSLINK_NEW);
253d62bc4baSyz 			return (RCM_FAILURE);
254d62bc4baSyz 		} else {
255d62bc4baSyz 			rcm_log_message(RCM_DEBUG, _("NET: unregistered %s\n"),
2565093e103SCathy Zhou 			    RCM_RESOURCE_PHYSLINK_NEW);
257d62bc4baSyz 			events_registered--;
258d62bc4baSyz 		}
259d62bc4baSyz 	}
260d62bc4baSyz 
2617c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate  * Since all we do is pass operations thru, we provide a general
2667c478bd9Sstevel@tonic-gate  * routine for passing through operations.
2677c478bd9Sstevel@tonic-gate  */
2687c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2697c478bd9Sstevel@tonic-gate static int
net_passthru(rcm_handle_t * hd,int op,const char * rsrc,uint_t flag,char ** reason,rcm_info_t ** dependent_reason,void * arg)2707c478bd9Sstevel@tonic-gate net_passthru(rcm_handle_t *hd, int op, const char *rsrc, uint_t flag,
2717c478bd9Sstevel@tonic-gate     char **reason, rcm_info_t **dependent_reason, void *arg)
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate 	net_cache_t	*node;
2747c478bd9Sstevel@tonic-gate 	char		*exported;
275d62bc4baSyz 	datalink_id_t	linkid;
276d62bc4baSyz 	int		len;
2777c478bd9Sstevel@tonic-gate 	int		rv;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	/*
2807c478bd9Sstevel@tonic-gate 	 * Lock the cache just long enough to extract information about this
2817c478bd9Sstevel@tonic-gate 	 * resource.
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
2847c478bd9Sstevel@tonic-gate 	node = cache_lookup(rsrc);
2857c478bd9Sstevel@tonic-gate 	if (!node) {
2867c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_WARNING,
2877c478bd9Sstevel@tonic-gate 		    _("NET: unrecognized resource %s\n"), rsrc);
2887c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
2897c478bd9Sstevel@tonic-gate 		return (RCM_SUCCESS);
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	/*
293d62bc4baSyz 	 * Since node could be freed after we drop cache_lock, allocate a
294d62bc4baSyz 	 * stack-local copy. We don't use malloc() because some of the
295d62bc4baSyz 	 * operations (such as NET_REMOVE) are not allowed to fail. Note
296d62bc4baSyz 	 * that exported is never more than MAXPATHLEN bytes.
2977c478bd9Sstevel@tonic-gate 	 */
298d62bc4baSyz 	len = strlen("SUNW_datalink/") + LINKID_STR_WIDTH + 1;
299d62bc4baSyz 	exported = alloca(len);
300d62bc4baSyz 	linkid = node->linkid;
301d62bc4baSyz 	(void) snprintf(exported, len, "SUNW_datalink/%u", linkid);
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	/*
3047c478bd9Sstevel@tonic-gate 	 * Remove notifications are unconditional in the RCM state model,
3057c478bd9Sstevel@tonic-gate 	 * so it's safe to remove the node from the cache at this point.
3067c478bd9Sstevel@tonic-gate 	 * And we need to remove it so that we will recognize it as a new
3077c478bd9Sstevel@tonic-gate 	 * resource following the reattachment of the resource.
3087c478bd9Sstevel@tonic-gate 	 */
3097c478bd9Sstevel@tonic-gate 	if (op == NET_REMOVE) {
3107c478bd9Sstevel@tonic-gate 		cache_remove(node);
3117c478bd9Sstevel@tonic-gate 		free_node(node);
3127c478bd9Sstevel@tonic-gate 	}
3137c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	switch (op) {
3167c478bd9Sstevel@tonic-gate 	case NET_SUSPEND:
3177c478bd9Sstevel@tonic-gate 		rv = rcm_request_suspend(hd, exported, flag,
3187c478bd9Sstevel@tonic-gate 		    (timespec_t *)arg, dependent_reason);
3197c478bd9Sstevel@tonic-gate 		break;
3207c478bd9Sstevel@tonic-gate 	case NET_OFFLINE:
3217c478bd9Sstevel@tonic-gate 		rv = rcm_request_offline(hd, exported, flag, dependent_reason);
3227c478bd9Sstevel@tonic-gate 		break;
3237c478bd9Sstevel@tonic-gate 	case NET_ONLINE:
3247c478bd9Sstevel@tonic-gate 		rv = rcm_notify_online(hd, exported, flag, dependent_reason);
3257c478bd9Sstevel@tonic-gate 		break;
3267c478bd9Sstevel@tonic-gate 	case NET_REMOVE:
3277c478bd9Sstevel@tonic-gate 		rv = rcm_notify_remove(hd, exported, flag, dependent_reason);
328d62bc4baSyz 		if (rv == RCM_SUCCESS) {
329d62bc4baSyz 			rcm_log_message(RCM_DEBUG,
330d62bc4baSyz 			    _("NET: mark link %d as removed\n"), linkid);
331d62bc4baSyz 
332d62bc4baSyz 			/*
333d62bc4baSyz 			 * Delete active linkprop before this active link
334d62bc4baSyz 			 * is deleted.
335d62bc4baSyz 			 */
3364ac67f02SAnurag S. Maskey 			(void) dladm_set_linkprop(dld_handle, linkid, NULL,
3374ac67f02SAnurag S. Maskey 			    NULL, 0, DLADM_OPT_ACTIVE);
3384ac67f02SAnurag S. Maskey 			(void) dladm_destroy_datalink_id(dld_handle, linkid,
339d62bc4baSyz 			    DLADM_OPT_ACTIVE);
340d62bc4baSyz 		}
3417c478bd9Sstevel@tonic-gate 		break;
3427c478bd9Sstevel@tonic-gate 	case NET_RESUME:
3437c478bd9Sstevel@tonic-gate 		rv = rcm_notify_resume(hd, exported, flag, dependent_reason);
3447c478bd9Sstevel@tonic-gate 		break;
3457c478bd9Sstevel@tonic-gate 	default:
3467c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_WARNING,
3477c478bd9Sstevel@tonic-gate 		    _("NET: bad RCM operation %1$d for %2$s\n"), op, exported);
3487c478bd9Sstevel@tonic-gate 		errno = EINVAL;
3497c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
3507c478bd9Sstevel@tonic-gate 	}
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate 	if (rv != RCM_SUCCESS) {
3537c478bd9Sstevel@tonic-gate 		char format[256];
3547c478bd9Sstevel@tonic-gate 		(void) snprintf(format, sizeof (format),
3557c478bd9Sstevel@tonic-gate 		    _("RCM operation on dependent %s did not succeed"),
3567c478bd9Sstevel@tonic-gate 		    exported);
3577c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_WARNING, "NET: %s\n", format);
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 	return (rv);
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate /*
3647c478bd9Sstevel@tonic-gate  * net_offline()
3657c478bd9Sstevel@tonic-gate  *
3667c478bd9Sstevel@tonic-gate  *	Determine dependents of the resource being offlined, and offline
3677c478bd9Sstevel@tonic-gate  *	them all.
3687c478bd9Sstevel@tonic-gate  */
3697c478bd9Sstevel@tonic-gate static int
net_offline(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** reason,rcm_info_t ** dependent_reason)3707c478bd9Sstevel@tonic-gate net_offline(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
3717c478bd9Sstevel@tonic-gate     char **reason, rcm_info_t **dependent_reason)
3727c478bd9Sstevel@tonic-gate {
3737c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
3747c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
3757c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
3767c478bd9Sstevel@tonic-gate 	assert(reason != NULL);
3777c478bd9Sstevel@tonic-gate 	assert(dependent_reason != NULL);
3787c478bd9Sstevel@tonic-gate 
379d62bc4baSyz 	rcm_log_message(RCM_TRACE1, _("NET: offline(%s)\n"), rsrc);
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate 	return (net_passthru(hd, NET_OFFLINE, rsrc, flags, reason,
3827c478bd9Sstevel@tonic-gate 	    dependent_reason, NULL));
3837c478bd9Sstevel@tonic-gate }
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate /*
3867c478bd9Sstevel@tonic-gate  * net_online()
3877c478bd9Sstevel@tonic-gate  *
388ae35285aSmeem  *	Online the previously offlined resource, and online its dependents.
3897c478bd9Sstevel@tonic-gate  */
3907c478bd9Sstevel@tonic-gate static int
net_online(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flag,char ** reason,rcm_info_t ** dependent_reason)3917c478bd9Sstevel@tonic-gate net_online(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **reason,
3927c478bd9Sstevel@tonic-gate     rcm_info_t **dependent_reason)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
3957c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
3967c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
3977c478bd9Sstevel@tonic-gate 
398d62bc4baSyz 	rcm_log_message(RCM_TRACE1, _("NET: online(%s)\n"), rsrc);
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	return (net_passthru(hd, NET_ONLINE, rsrc, flag, reason,
4017c478bd9Sstevel@tonic-gate 	    dependent_reason, NULL));
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate /*
4057c478bd9Sstevel@tonic-gate  * net_getinfo()
4067c478bd9Sstevel@tonic-gate  *
4077c478bd9Sstevel@tonic-gate  *	Gather usage information for this resource.
4087c478bd9Sstevel@tonic-gate  *
4097c478bd9Sstevel@tonic-gate  *	Locking: the cache is locked while this routine looks up the
4107c478bd9Sstevel@tonic-gate  *	resource and extracts copies of any piece of information it needs.
4117c478bd9Sstevel@tonic-gate  *	The cache is then unlocked, and this routine performs the rest of
4127c478bd9Sstevel@tonic-gate  *	its functions without touching any part of the cache.
4137c478bd9Sstevel@tonic-gate  */
4147c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4157c478bd9Sstevel@tonic-gate static int
net_getinfo(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flag,char ** info,char ** errstr,nvlist_t * proplist,rcm_info_t ** depend_info)4167c478bd9Sstevel@tonic-gate net_getinfo(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag,
4177c478bd9Sstevel@tonic-gate     char **info, char **errstr, nvlist_t *proplist, rcm_info_t **depend_info)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	int		len;
420d62bc4baSyz 	dladm_status_t	status;
421d62bc4baSyz 	char		link[MAXLINKNAMELEN];
422d62bc4baSyz 	char		errmsg[DLADM_STRSIZE];
4237c478bd9Sstevel@tonic-gate 	char		*exported;
4247c478bd9Sstevel@tonic-gate 	const char	*info_fmt;
4257c478bd9Sstevel@tonic-gate 	net_cache_t	*node;
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
4287c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
4297c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
4307c478bd9Sstevel@tonic-gate 	assert(info != NULL);
4317c478bd9Sstevel@tonic-gate 	assert(depend_info != NULL);
4327c478bd9Sstevel@tonic-gate 
433d62bc4baSyz 	rcm_log_message(RCM_TRACE1, _("NET: getinfo(%s)\n"), rsrc);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	info_fmt = _("Network interface %s");
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
4387c478bd9Sstevel@tonic-gate 	node = cache_lookup(rsrc);
4397c478bd9Sstevel@tonic-gate 	if (!node) {
4407c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_WARNING,
4417c478bd9Sstevel@tonic-gate 		    _("NET: unrecognized resource %s\n"), rsrc);
4427c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
4437c478bd9Sstevel@tonic-gate 		errno = ENOENT;
4447c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
4457c478bd9Sstevel@tonic-gate 	}
446d62bc4baSyz 
447d62bc4baSyz 	len = strlen(info_fmt) + MAXLINKNAMELEN + 1;
4484ac67f02SAnurag S. Maskey 	if ((status = dladm_datalink_id2info(dld_handle, node->linkid, NULL,
4494ac67f02SAnurag S. Maskey 	    NULL, NULL, link, sizeof (link))) != DLADM_STATUS_OK) {
450d62bc4baSyz 		rcm_log_message(RCM_ERROR,
451d62bc4baSyz 		    _("NET: usage(%s) get link name failure(%s)\n"),
452d62bc4baSyz 		    node->resource, dladm_status2str(status, errmsg));
4537c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cache_lock);
4547c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
455d62bc4baSyz 	} else if ((*info = (char *)malloc(len)) == NULL) {
4567c478bd9Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, _("NET: malloc failure"));
457d62bc4baSyz 		(void) mutex_unlock(&cache_lock);
4587c478bd9Sstevel@tonic-gate 		return (RCM_FAILURE);
4597c478bd9Sstevel@tonic-gate 	}
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	/* Fill in the string */
462d62bc4baSyz 	(void) snprintf(*info, len, info_fmt, link);
463d62bc4baSyz 
464d62bc4baSyz 	len = strlen("SUNW_datalink/") + LINKID_STR_WIDTH + 1;
465d62bc4baSyz 	exported = malloc(len);
466d62bc4baSyz 	if (!exported) {
467d62bc4baSyz 		rcm_log_message(RCM_ERROR, _("NET: allocation failure"));
468d62bc4baSyz 		free(*info);
469d62bc4baSyz 		(void) mutex_unlock(&cache_lock);
470d62bc4baSyz 		return (RCM_FAILURE);
471d62bc4baSyz 	}
472d62bc4baSyz 	(void) snprintf(exported, len, "SUNW_datalink/%u", node->linkid);
473d62bc4baSyz 	(void) mutex_unlock(&cache_lock);
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	/* Get dependent info if requested */
4767c478bd9Sstevel@tonic-gate 	if ((flag & RCM_INCLUDE_DEPENDENT) || (flag & RCM_INCLUDE_SUBTREE)) {
4777c478bd9Sstevel@tonic-gate 		(void) rcm_get_info(hd, exported, flag, depend_info);
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 	(void) nvlist_add_string(proplist, RCM_CLIENT_NAME, "SunOS");
4817c478bd9Sstevel@tonic-gate 	(void) nvlist_add_string_array(proplist, RCM_CLIENT_EXPORTS,
4827c478bd9Sstevel@tonic-gate 	    &exported, 1);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	free(exported);
4857c478bd9Sstevel@tonic-gate 	return (RCM_SUCCESS);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate /*
4897c478bd9Sstevel@tonic-gate  * net_suspend()
4907c478bd9Sstevel@tonic-gate  *
4917c478bd9Sstevel@tonic-gate  *	Notify all dependents that the resource is being suspended.
4927c478bd9Sstevel@tonic-gate  *	Since no real operation is involved, QUERY or not doesn't matter.
4937c478bd9Sstevel@tonic-gate  *
4947c478bd9Sstevel@tonic-gate  *	Locking: the cache is only used to retrieve some information about
4957c478bd9Sstevel@tonic-gate  *	this resource, so it is only locked during that retrieval.
4967c478bd9Sstevel@tonic-gate  */
4977c478bd9Sstevel@tonic-gate static int
net_suspend(rcm_handle_t * hd,char * rsrc,id_t id,timespec_t * interval,uint_t flag,char ** reason,rcm_info_t ** dependent_reason)4987c478bd9Sstevel@tonic-gate net_suspend(rcm_handle_t *hd, char *rsrc, id_t id, timespec_t *interval,
4997c478bd9Sstevel@tonic-gate     uint_t flag, char **reason, rcm_info_t **dependent_reason)
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
5027c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
5037c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
5047c478bd9Sstevel@tonic-gate 	assert(interval != NULL);
5057c478bd9Sstevel@tonic-gate 	assert(reason != NULL);
5067c478bd9Sstevel@tonic-gate 	assert(dependent_reason != NULL);
5077c478bd9Sstevel@tonic-gate 
508d62bc4baSyz 	rcm_log_message(RCM_TRACE1, _("NET: suspend(%s)\n"), rsrc);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	return (net_passthru(hd, NET_SUSPEND, rsrc, flag, reason,
5117c478bd9Sstevel@tonic-gate 	    dependent_reason, (void *)interval));
5127c478bd9Sstevel@tonic-gate }
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate /*
5157c478bd9Sstevel@tonic-gate  * net_resume()
5167c478bd9Sstevel@tonic-gate  *
5177c478bd9Sstevel@tonic-gate  *	Resume all the dependents of a suspended network.
5187c478bd9Sstevel@tonic-gate  *
5197c478bd9Sstevel@tonic-gate  *	Locking: the cache is only used to retrieve some information about
5207c478bd9Sstevel@tonic-gate  *	this resource, so it is only locked during that retrieval.
5217c478bd9Sstevel@tonic-gate  */
5227c478bd9Sstevel@tonic-gate static int
net_resume(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flag,char ** info,rcm_info_t ** dependent_info)5237c478bd9Sstevel@tonic-gate net_resume(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **info,
5247c478bd9Sstevel@tonic-gate     rcm_info_t **dependent_info)
5257c478bd9Sstevel@tonic-gate {
5267c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
5277c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
5287c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
5297c478bd9Sstevel@tonic-gate 	assert(info != NULL);
5307c478bd9Sstevel@tonic-gate 	assert(dependent_info != NULL);
5317c478bd9Sstevel@tonic-gate 
532d62bc4baSyz 	rcm_log_message(RCM_TRACE1, _("NET: resume(%s)\n"), rsrc);
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	return (net_passthru(hd, NET_RESUME, rsrc, flag, info, dependent_info,
5357c478bd9Sstevel@tonic-gate 	    NULL));
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate /*
5397c478bd9Sstevel@tonic-gate  * net_remove()
5407c478bd9Sstevel@tonic-gate  *
5417c478bd9Sstevel@tonic-gate  *	This is another NO-OP for us, we just passthru the information.  We
5427c478bd9Sstevel@tonic-gate  *	don't need to remove it from our cache.  We don't unregister
5437c478bd9Sstevel@tonic-gate  *	interest at this point either; the network device name is still
5447c478bd9Sstevel@tonic-gate  *	around.  This way we don't have to change this logic when we
5457c478bd9Sstevel@tonic-gate  *	gain the ability to learn about DR attach operations.
5467c478bd9Sstevel@tonic-gate  */
5477c478bd9Sstevel@tonic-gate static int
net_remove(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flag,char ** info,rcm_info_t ** dependent_info)5487c478bd9Sstevel@tonic-gate net_remove(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flag, char **info,
5497c478bd9Sstevel@tonic-gate     rcm_info_t **dependent_info)
5507c478bd9Sstevel@tonic-gate {
5517c478bd9Sstevel@tonic-gate 	assert(hd != NULL);
5527c478bd9Sstevel@tonic-gate 	assert(rsrc != NULL);
5537c478bd9Sstevel@tonic-gate 	assert(id == (id_t)0);
5547c478bd9Sstevel@tonic-gate 	assert(info != NULL);
5557c478bd9Sstevel@tonic-gate 	assert(dependent_info != NULL);
5567c478bd9Sstevel@tonic-gate 
557d62bc4baSyz 	rcm_log_message(RCM_TRACE1, _("NET: remove(%s)\n"), rsrc);
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	return (net_passthru(hd, NET_REMOVE, rsrc, flag, info, dependent_info,
5607c478bd9Sstevel@tonic-gate 	    NULL));
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate /*
5647c478bd9Sstevel@tonic-gate  * Cache management routines.  Note that the cache is implemented as a
5657c478bd9Sstevel@tonic-gate  * trivial linked list, and is only required because RCM doesn't
5667c478bd9Sstevel@tonic-gate  * provide enough state about our own registrations back to us.  This
5677c478bd9Sstevel@tonic-gate  * linked list implementation probably clobbers the CPU cache pretty
5687c478bd9Sstevel@tonic-gate  * well.
5697c478bd9Sstevel@tonic-gate  */
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate /*
5727c478bd9Sstevel@tonic-gate  * cache_lookup()
5737c478bd9Sstevel@tonic-gate  *
5747c478bd9Sstevel@tonic-gate  * Get a cache node for a resource.  Call with cache lock held.
5757c478bd9Sstevel@tonic-gate  */
5767c478bd9Sstevel@tonic-gate static net_cache_t *
cache_lookup(const char * resource)5777c478bd9Sstevel@tonic-gate cache_lookup(const char *resource)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate 	net_cache_t *probe;
5807c478bd9Sstevel@tonic-gate 	probe = cache_head.next;
5817c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
5827c478bd9Sstevel@tonic-gate 		if (probe->resource &&
5837c478bd9Sstevel@tonic-gate 		    (strcmp(resource, probe->resource) == 0)) {
5847c478bd9Sstevel@tonic-gate 			return (probe);
5857c478bd9Sstevel@tonic-gate 		}
5867c478bd9Sstevel@tonic-gate 		probe = probe->next;
5877c478bd9Sstevel@tonic-gate 	}
5887c478bd9Sstevel@tonic-gate 	return (NULL);
5897c478bd9Sstevel@tonic-gate }
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate /*
5927c478bd9Sstevel@tonic-gate  * free_node()
5937c478bd9Sstevel@tonic-gate  *
5947c478bd9Sstevel@tonic-gate  * Free a node.  Make sure it isn't in the list!
5957c478bd9Sstevel@tonic-gate  */
5967c478bd9Sstevel@tonic-gate static void
free_node(net_cache_t * node)5977c478bd9Sstevel@tonic-gate free_node(net_cache_t *node)
5987c478bd9Sstevel@tonic-gate {
5997c478bd9Sstevel@tonic-gate 	if (node) {
6007c478bd9Sstevel@tonic-gate 		free(node->resource);
6017c478bd9Sstevel@tonic-gate 		free(node);
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate }
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate /*
6067c478bd9Sstevel@tonic-gate  * cache_insert()
6077c478bd9Sstevel@tonic-gate  *
6087c478bd9Sstevel@tonic-gate  * Call with the cache_lock held.
6097c478bd9Sstevel@tonic-gate  */
6107c478bd9Sstevel@tonic-gate static void
cache_insert(net_cache_t * node)6117c478bd9Sstevel@tonic-gate cache_insert(net_cache_t *node)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate 	/* insert at the head for best performance */
6147c478bd9Sstevel@tonic-gate 	node->next = cache_head.next;
6157c478bd9Sstevel@tonic-gate 	node->prev = &cache_head;
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	node->next->prev = node;
6187c478bd9Sstevel@tonic-gate 	node->prev->next = node;
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate /*
6227c478bd9Sstevel@tonic-gate  * cache_remove()
6237c478bd9Sstevel@tonic-gate  *
6247c478bd9Sstevel@tonic-gate  * Call with the cache_lock held.
6257c478bd9Sstevel@tonic-gate  */
6267c478bd9Sstevel@tonic-gate static void
cache_remove(net_cache_t * node)6277c478bd9Sstevel@tonic-gate cache_remove(net_cache_t *node)
6287c478bd9Sstevel@tonic-gate {
6297c478bd9Sstevel@tonic-gate 	node->next->prev = node->prev;
6307c478bd9Sstevel@tonic-gate 	node->prev->next = node->next;
6317c478bd9Sstevel@tonic-gate 	node->next = NULL;
6327c478bd9Sstevel@tonic-gate 	node->prev = NULL;
6337c478bd9Sstevel@tonic-gate }
6347c478bd9Sstevel@tonic-gate 
6357c478bd9Sstevel@tonic-gate /*
6367c478bd9Sstevel@tonic-gate  * devfs_entry()
6377c478bd9Sstevel@tonic-gate  *
6387c478bd9Sstevel@tonic-gate  * Call with the cache_lock held.
6397c478bd9Sstevel@tonic-gate  */
6407c478bd9Sstevel@tonic-gate /*ARGSUSED*/
6417c478bd9Sstevel@tonic-gate static int
devfs_entry(di_node_t node,di_minor_t minor,void * arg)6427c478bd9Sstevel@tonic-gate devfs_entry(di_node_t node, di_minor_t minor, void *arg)
6437c478bd9Sstevel@tonic-gate {
6447c478bd9Sstevel@tonic-gate 	char		*devfspath;
6457c478bd9Sstevel@tonic-gate 	char		resource[MAXPATHLEN];
646d62bc4baSyz 	char		dev[MAXNAMELEN];
647d62bc4baSyz 	datalink_id_t	linkid;
648d62bc4baSyz 	char		*drv;
6497c478bd9Sstevel@tonic-gate 	char		*cp;
6507c478bd9Sstevel@tonic-gate 	net_cache_t	*probe;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	cp = di_minor_nodetype(minor);
6537c478bd9Sstevel@tonic-gate 	if ((cp == NULL) || (strcmp(cp, DDI_NT_NET))) {
6547c478bd9Sstevel@tonic-gate 		/* doesn't look like a network device */
6557c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 
658d62bc4baSyz 	drv = di_driver_name(node);
659d62bc4baSyz 	if (drv == NULL) {
6607c478bd9Sstevel@tonic-gate 		/* what else can we do? */
6617c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
6627c478bd9Sstevel@tonic-gate 	}
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	devfspath = di_devfs_path(node);
6657c478bd9Sstevel@tonic-gate 	if (!devfspath) {
6667c478bd9Sstevel@tonic-gate 		/* no devfs path?!? */
667d62bc4baSyz 		rcm_log_message(RCM_DEBUG, _("NET: missing devfs path\n"));
6687c478bd9Sstevel@tonic-gate 		return (DI_WALK_CONTINUE);
6697c478bd9Sstevel@tonic-gate 	}
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate 	if (strncmp("/pseudo", devfspath, strlen("/pseudo")) == 0) {
672210db224Sericheng 		/* ignore pseudo devices, probably not really NICs */
673d62bc4baSyz 		rcm_log_message(RCM_DEBUG,
674d62bc4baSyz 		    _("NET: ignoring pseudo device %s\n"), devfspath);
675210db224Sericheng 		di_devfs_path_free(devfspath);
676210db224Sericheng 		return (DI_WALK_CONTINUE);
6777c478bd9Sstevel@tonic-gate 	}
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	(void) snprintf(resource, sizeof (resource), "/devices%s", devfspath);
6807c478bd9Sstevel@tonic-gate 	di_devfs_path_free(devfspath);
6817c478bd9Sstevel@tonic-gate 
682d62bc4baSyz 	(void) snprintf(dev, sizeof (dev), "%s%d", drv, di_instance(node));
6834ac67f02SAnurag S. Maskey 	if (dladm_dev2linkid(dld_handle, dev, &linkid) != DLADM_STATUS_OK) {
684d62bc4baSyz 		rcm_log_message(RCM_DEBUG,
685d62bc4baSyz 		    _("NET: failed to find the linkid for %s\n"), dev);
686d62bc4baSyz 		return (DI_WALK_CONTINUE);
687d62bc4baSyz 	}
688d62bc4baSyz 
6897c478bd9Sstevel@tonic-gate 	probe = cache_lookup(resource);
6907c478bd9Sstevel@tonic-gate 	if (probe != NULL) {
691d62bc4baSyz 		rcm_log_message(RCM_DEBUG,
692d62bc4baSyz 		    _("NET: %s already registered (linkid %u)\n"),
693d62bc4baSyz 		    resource, linkid);
694d62bc4baSyz 		probe->linkid = linkid;
6957c478bd9Sstevel@tonic-gate 		probe->flags &= ~(CACHE_STALE);
6967c478bd9Sstevel@tonic-gate 	} else {
697d62bc4baSyz 		rcm_log_message(RCM_DEBUG,
698d62bc4baSyz 		    _("NET: %s is new resource (linkid %u)\n"),
699d62bc4baSyz 		    resource, linkid);
7007c478bd9Sstevel@tonic-gate 		probe = calloc(1, sizeof (net_cache_t));
7017c478bd9Sstevel@tonic-gate 		if (!probe) {
7027c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR, _("NET: malloc failure"));
7037c478bd9Sstevel@tonic-gate 			return (DI_WALK_CONTINUE);
7047c478bd9Sstevel@tonic-gate 		}
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 		probe->resource = strdup(resource);
707d62bc4baSyz 		probe->linkid = linkid;
7087c478bd9Sstevel@tonic-gate 
709d62bc4baSyz 		if (!probe->resource) {
7107c478bd9Sstevel@tonic-gate 			free_node(probe);
7117c478bd9Sstevel@tonic-gate 			return (DI_WALK_CONTINUE);
7127c478bd9Sstevel@tonic-gate 		}
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 		probe->flags |= CACHE_NEW;
7157c478bd9Sstevel@tonic-gate 		cache_insert(probe);
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	return (DI_WALK_CONTINUE);
7197c478bd9Sstevel@tonic-gate }
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate /*
7227c478bd9Sstevel@tonic-gate  * update_cache()
7237c478bd9Sstevel@tonic-gate  *
7247c478bd9Sstevel@tonic-gate  * The devinfo tree walking code is lifted from ifconfig.c.
7257c478bd9Sstevel@tonic-gate  */
7267c478bd9Sstevel@tonic-gate static void
update_cache(rcm_handle_t * hd)7277c478bd9Sstevel@tonic-gate update_cache(rcm_handle_t *hd)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate 	net_cache_t	*probe;
7307c478bd9Sstevel@tonic-gate 	di_node_t	root;
7317c478bd9Sstevel@tonic-gate 	int		rv;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	/* first we walk the entire cache, marking each entry stale */
7367c478bd9Sstevel@tonic-gate 	probe = cache_head.next;
7377c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
7387c478bd9Sstevel@tonic-gate 		probe->flags |= CACHE_STALE;
7397c478bd9Sstevel@tonic-gate 		probe = probe->next;
7407c478bd9Sstevel@tonic-gate 	}
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	root = di_init("/", DINFOSUBTREE | DINFOMINOR);
7437c478bd9Sstevel@tonic-gate 	if (root == DI_NODE_NIL) {
7447c478bd9Sstevel@tonic-gate 		goto done;
7457c478bd9Sstevel@tonic-gate 	}
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 	(void) di_walk_minor(root, DDI_NT_NET, DI_CHECK_ALIAS, NULL,
7487c478bd9Sstevel@tonic-gate 	    devfs_entry);
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	di_fini(root);
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate 	probe = cache_head.next;
7537c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
7547c478bd9Sstevel@tonic-gate 		net_cache_t *freeit;
7557c478bd9Sstevel@tonic-gate 		if (probe->flags & CACHE_STALE) {
7567c478bd9Sstevel@tonic-gate 			(void) rcm_unregister_interest(hd, probe->resource, 0);
757d62bc4baSyz 			rcm_log_message(RCM_DEBUG, _("NET: unregistered %s\n"),
7587c478bd9Sstevel@tonic-gate 			    probe->resource);
7597c478bd9Sstevel@tonic-gate 			freeit = probe;
7607c478bd9Sstevel@tonic-gate 			probe = probe->next;
7617c478bd9Sstevel@tonic-gate 			cache_remove(freeit);
7627c478bd9Sstevel@tonic-gate 			free_node(freeit);
7637c478bd9Sstevel@tonic-gate 			continue;
7647c478bd9Sstevel@tonic-gate 		}
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 		if (!(probe->flags & CACHE_NEW)) {
7677c478bd9Sstevel@tonic-gate 			probe = probe->next;
7687c478bd9Sstevel@tonic-gate 			continue;
7697c478bd9Sstevel@tonic-gate 		}
7707c478bd9Sstevel@tonic-gate 
771d62bc4baSyz 		rcm_log_message(RCM_DEBUG, _("NET: registering %s\n"),
7727c478bd9Sstevel@tonic-gate 		    probe->resource);
7737c478bd9Sstevel@tonic-gate 		rv = rcm_register_interest(hd, probe->resource, 0, NULL);
7747c478bd9Sstevel@tonic-gate 		if (rv != RCM_SUCCESS) {
7757c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_ERROR,
7767c478bd9Sstevel@tonic-gate 			    _("NET: failed to register %s\n"),
7777c478bd9Sstevel@tonic-gate 			    probe->resource);
7787c478bd9Sstevel@tonic-gate 		} else {
7797c478bd9Sstevel@tonic-gate 			rcm_log_message(RCM_DEBUG,
780d62bc4baSyz 			    _("NET: registered %s as SUNW_datalink/%u\n"),
781d62bc4baSyz 			    probe->resource, probe->linkid);
7827c478bd9Sstevel@tonic-gate 			probe->flags &= ~(CACHE_NEW);
7837c478bd9Sstevel@tonic-gate 		}
7847c478bd9Sstevel@tonic-gate 		probe = probe->next;
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate done:
7887c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
7897c478bd9Sstevel@tonic-gate }
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate /*
7927c478bd9Sstevel@tonic-gate  * free_cache()
7937c478bd9Sstevel@tonic-gate  */
7947c478bd9Sstevel@tonic-gate static void
free_cache(void)7957c478bd9Sstevel@tonic-gate free_cache(void)
7967c478bd9Sstevel@tonic-gate {
7977c478bd9Sstevel@tonic-gate 	net_cache_t *probe;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cache_lock);
8007c478bd9Sstevel@tonic-gate 	probe = cache_head.next;
8017c478bd9Sstevel@tonic-gate 	while (probe != &cache_tail) {
8027c478bd9Sstevel@tonic-gate 		cache_remove(probe);
8037c478bd9Sstevel@tonic-gate 		free_node(probe);
8047c478bd9Sstevel@tonic-gate 		probe = cache_head.next;
8057c478bd9Sstevel@tonic-gate 	}
8067c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cache_lock);
8077c478bd9Sstevel@tonic-gate }
808210db224Sericheng 
809210db224Sericheng /*
810d62bc4baSyz  * net_notify_event - Project private implementation to receive new
811d62bc4baSyz  *			resource events. It intercepts all new resource
812d62bc4baSyz  *			events. If the new resource is a network resource,
8130dc974a9SCathy Zhou  *			update the physical link cache.
814210db224Sericheng  */
815d62bc4baSyz /*ARGSUSED*/
816d62bc4baSyz static int
net_notify_event(rcm_handle_t * hd,char * rsrc,id_t id,uint_t flags,char ** errorp,nvlist_t * nvl,rcm_info_t ** depend_info)817d62bc4baSyz net_notify_event(rcm_handle_t *hd, char *rsrc, id_t id, uint_t flags,
818d62bc4baSyz     char **errorp, nvlist_t *nvl, rcm_info_t **depend_info)
819d62bc4baSyz {
8205093e103SCathy Zhou 	nvpair_t	*nvp = NULL;
8215093e103SCathy Zhou 	uint64_t	id64 = (uint64_t)DATALINK_INVALID_LINKID;
8225093e103SCathy Zhou 	boolean_t	reconfigured = B_FALSE;
8235093e103SCathy Zhou 
824d62bc4baSyz 	rcm_log_message(RCM_TRACE1, _("NET: notify_event(%s)\n"), rsrc);
825210db224Sericheng 
8265093e103SCathy Zhou 	if (strcmp(rsrc, RCM_RESOURCE_PHYSLINK_NEW) != 0) {
827d62bc4baSyz 		rcm_log_message(RCM_INFO,
828d62bc4baSyz 		    _("NET: unrecognized event for %s\n"), rsrc);
829d62bc4baSyz 		errno = EINVAL;
830d62bc4baSyz 		return (RCM_FAILURE);
831d62bc4baSyz 	}
832d62bc4baSyz 
833d62bc4baSyz 	/* Update cache to reflect latest physical links */
834d62bc4baSyz 	update_cache(hd);
835d62bc4baSyz 
8365093e103SCathy Zhou 	while ((nvp = nvlist_next_nvpair(nvl, nvp)) != NULL) {
8375093e103SCathy Zhou 		if (strcmp(nvpair_name(nvp), RCM_NV_RECONFIGURED) == 0) {
8385093e103SCathy Zhou 			if (nvpair_value_boolean_value(nvp,
8395093e103SCathy Zhou 			    &reconfigured) != 0) {
8405093e103SCathy Zhou 				rcm_log_message(RCM_INFO,
8415093e103SCathy Zhou 				    _("NET: unrecognized %s event data\n"),
8425093e103SCathy Zhou 				    RCM_NV_RECONFIGURED);
8435093e103SCathy Zhou 				errno = EINVAL;
8445093e103SCathy Zhou 				return (RCM_FAILURE);
8455093e103SCathy Zhou 			}
8465093e103SCathy Zhou 
8475093e103SCathy Zhou 			rcm_log_message(RCM_TRACE1,
8485093e103SCathy Zhou 			    "NET: %s event data (%sreconfiguration)\n",
8495093e103SCathy Zhou 			    RCM_NV_RECONFIGURED, reconfigured ? "" : "not ");
8505093e103SCathy Zhou 		}
8515093e103SCathy Zhou 
8525093e103SCathy Zhou 		if (strcmp(nvpair_name(nvp), RCM_NV_LINKID) == 0) {
8535093e103SCathy Zhou 			if (nvpair_value_uint64(nvp, &id64) != 0) {
8545093e103SCathy Zhou 				rcm_log_message(RCM_INFO,
8555093e103SCathy Zhou 				    _("NET: unrecognized %s event data\n"),
8565093e103SCathy Zhou 				    RCM_NV_LINKID);
8575093e103SCathy Zhou 				errno = EINVAL;
8585093e103SCathy Zhou 				return (RCM_FAILURE);
8595093e103SCathy Zhou 			}
8605093e103SCathy Zhou 
8615093e103SCathy Zhou 			rcm_log_message(RCM_TRACE1,
8625093e103SCathy Zhou 			    "NET: %s event data (linkid %d)\n", RCM_NV_LINKID,
8635093e103SCathy Zhou 			    (datalink_id_t)id64);
8645093e103SCathy Zhou 		}
8655093e103SCathy Zhou 	}
8665093e103SCathy Zhou 
8675093e103SCathy Zhou 	if ((datalink_id_t)id64 == DATALINK_INVALID_LINKID) {
8685093e103SCathy Zhou 		rcm_log_message(RCM_INFO, _("NET: invalid datalink\n"));
8695093e103SCathy Zhou 		errno = EINVAL;
8705093e103SCathy Zhou 		return (RCM_FAILURE);
8715093e103SCathy Zhou 	}
8725093e103SCathy Zhou 
8735093e103SCathy Zhou 	/*
8745093e103SCathy Zhou 	 * If this is device reconfiguration, populate the LINK_NEW event
8755093e103SCathy Zhou 	 * to start the DR process.
8765093e103SCathy Zhou 	 */
8775093e103SCathy Zhou 	if (reconfigured) {
8785093e103SCathy Zhou 		nvlist_t *nnvl = NULL;
8795093e103SCathy Zhou 
8805093e103SCathy Zhou 		rcm_log_message(RCM_TRACE1,
8815093e103SCathy Zhou 		    "NET: reconfigured data-link (id %d)\n",
8825093e103SCathy Zhou 		    (datalink_id_t)id64);
8835093e103SCathy Zhou 
8845093e103SCathy Zhou 		if ((nvlist_alloc(&nnvl, 0, 0) != 0) || (nvlist_add_uint64(nnvl,
8855093e103SCathy Zhou 		    RCM_NV_LINKID, id64) != 0) || (rcm_notify_event(hd,
8865093e103SCathy Zhou 		    RCM_RESOURCE_LINK_NEW, 0, nnvl, NULL) != RCM_SUCCESS)) {
8875093e103SCathy Zhou 			nvlist_free(nnvl);
8885093e103SCathy Zhou 			rcm_log_message(RCM_INFO,
8895093e103SCathy Zhou 			    _("NET: notify %s event failed\n"),
8905093e103SCathy Zhou 			    RCM_RESOURCE_LINK_NEW);
8915093e103SCathy Zhou 			errno = EINVAL;
8925093e103SCathy Zhou 			return (RCM_FAILURE);
8935093e103SCathy Zhou 		}
8945093e103SCathy Zhou 		nvlist_free(nnvl);
8955093e103SCathy Zhou 	}
8965093e103SCathy Zhou 
897d62bc4baSyz 	rcm_log_message(RCM_TRACE1,
898d62bc4baSyz 	    _("NET: notify_event: device configuration complete\n"));
899d62bc4baSyz 
900d62bc4baSyz 	return (RCM_SUCCESS);
901d62bc4baSyz }
902