1d62bc4byz/*
2d62bc4byz * CDDL HEADER START
3d62bc4byz *
4d62bc4byz * The contents of this file are subject to the terms of the
5d62bc4byz * Common Development and Distribution License (the "License").
6d62bc4byz * You may not use this file except in compliance with the License.
7d62bc4byz *
8d62bc4byz * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d62bc4byz * or http://www.opensolaris.org/os/licensing.
10d62bc4byz * See the License for the specific language governing permissions
11d62bc4byz * and limitations under the License.
12d62bc4byz *
13d62bc4byz * When distributing Covered Code, include this CDDL HEADER in each
14d62bc4byz * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d62bc4byz * If applicable, add the following below this CDDL HEADER, with the
16d62bc4byz * fields enclosed by brackets "[]" replaced with your own identifying
17d62bc4byz * information: Portions Copyright [yyyy] [name of copyright owner]
18d62bc4byz *
19d62bc4byz * CDDL HEADER END
20d62bc4byz */
21d62bc4byz/*
222b24ab6Sebastien Roy * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23d62bc4byz * Use is subject to license terms.
24d62bc4byz */
25d62bc4byz
26d62bc4byz/*
27d62bc4byz * vnode ops for the /dev/net directory
28d62bc4byz *
29d62bc4byz *	The lookup is based on the internal vanity naming node table.  We also
30d62bc4byz *	override readdir in order to delete net nodes no longer	in-use.
31d62bc4byz */
32d62bc4byz
33d62bc4byz#include <sys/types.h>
34d62bc4byz#include <sys/param.h>
35d62bc4byz#include <sys/sysmacros.h>
36d62bc4byz#include <sys/sunndi.h>
37d62bc4byz#include <fs/fs_subr.h>
38d62bc4byz#include <sys/fs/dv_node.h>
39d62bc4byz#include <sys/fs/sdev_impl.h>
40d62bc4byz#include <sys/policy.h>
41d62bc4byz#include <sys/zone.h>
42d62bc4byz#include <sys/dls.h>
43d62bc4byz
44d62bc4byzstruct vnodeops		*devnet_vnodeops;
45d62bc4byz
46d62bc4byz/*
47d62bc4byz * Check if a net sdev_node is still valid - i.e. it represents a current
48d62bc4byz * network link.
49d62bc4byz * This serves two purposes
50d62bc4byz *	- only valid net nodes are returned during lookup() and readdir().
51d62bc4byz *	- since net sdev_nodes are not actively destroyed when a network link
52d62bc4byz *	  goes away, we use the validator to do deferred cleanup i.e. when such
53d62bc4byz *	  nodes are encountered during subsequent lookup() and readdir().
54d62bc4byz */
55d62bc4byzint
56d62bc4byzdevnet_validate(struct sdev_node *dv)
57d62bc4byz{
58d62bc4byz	datalink_id_t linkid;
592b24ab6Sebastien Roy	zoneid_t zoneid;
60d62bc4byz
61d62bc4byz	ASSERT(dv->sdev_state == SDEV_READY);
62d62bc4byz
632b24ab6Sebastien Roy	if (dls_mgmt_get_linkid(dv->sdev_name, &linkid) != 0)
642b24ab6Sebastien Roy		return (SDEV_VTOR_INVALID);
652b24ab6Sebastien Roy	if (SDEV_IS_GLOBAL(dv))
662b24ab6Sebastien Roy		return (SDEV_VTOR_VALID);
672b24ab6Sebastien Roy	zoneid = getzoneid();
682b24ab6Sebastien Roy	return (zone_check_datalink(&zoneid, linkid) == 0 ?
692b24ab6Sebastien Roy	    SDEV_VTOR_VALID : SDEV_VTOR_INVALID);
70d62bc4byz}
71d62bc4byz
72d62bc4byz/*
73d62bc4byz * This callback is invoked from devname_lookup_func() to create
74d62bc4byz * a net entry when the node is not found in the cache.
75d62bc4byz */
76d62bc4byzstatic int
77d62bc4byzdevnet_create_rvp(const char *nm, struct vattr *vap, dls_dl_handle_t *ddhp)
78d62bc4byz{
79d62bc4byz	timestruc_t now;
80d62bc4byz	dev_t dev;
81d62bc4byz	int error;
82d62bc4byz
83d62bc4byz	if ((error = dls_devnet_open(nm, ddhp, &dev)) != 0) {
84d62bc4byz		sdcmn_err12(("devnet_create_rvp: not a valid vanity name "
85d62bc4byz		    "network node: %s\n", nm));
86d62bc4byz		return (error);
87d62bc4byz	}
88d62bc4byz
89d62bc4byz	/*
90d62bc4byz	 * This is a valid network device (at least at this point in time).
91d62bc4byz	 * Create the node by setting the attribute; the rest is taken care
92d62bc4byz	 * of by devname_lookup_func().
93d62bc4byz	 */
94d62bc4byz	*vap = sdev_vattr_chr;
95d62bc4byz	vap->va_mode |= 0666;
96d62bc4byz	vap->va_rdev = dev;
97d62bc4byz
98d62bc4byz	gethrestime(&now);
99d62bc4byz	vap->va_atime = now;
100d62bc4byz	vap->va_mtime = now;
101d62bc4byz	vap->va_ctime = now;
102d62bc4byz	return (0);
103d62bc4byz}
104d62bc4byz
105d62bc4byz/*
106d62bc4byz * Lookup for /dev/net directory
107d62bc4byz *	If the entry does not exist, the devnet_create_rvp() callback
108d62bc4byz *	is invoked to create it.  Nodes do not persist across reboot.
109d62bc4byz */
110d62bc4byz/*ARGSUSED3*/
111d62bc4byzstatic int
112d62bc4byzdevnet_lookup(struct vnode *dvp, char *nm, struct vnode **vpp,
113d62bc4byz    struct pathname *pnp, int flags, struct vnode *rdir, struct cred *cred,
114d62bc4byz    caller_context_t *ct, int *direntflags, pathname_t *realpnp)
115d62bc4byz{
116d62bc4byz	struct sdev_node *ddv = VTOSDEV(dvp);
117d62bc4byz	struct sdev_node *dv = NULL;
118d62bc4byz	dls_dl_handle_t ddh = NULL;
119d62bc4byz	struct vattr vattr;
120d62bc4byz	int nmlen;
121d62bc4byz	int error = ENOENT;
122d62bc4byz
123d62bc4byz	if (SDEVTOV(ddv)->v_type != VDIR)
124d62bc4byz		return (ENOTDIR);
125d62bc4byz
126d62bc4byz	/*
127d62bc4byz	 * Empty name or ., return node itself.
128d62bc4byz	 */
129d62bc4byz	nmlen = strlen(nm);
130d62bc4byz	if ((nmlen == 0) || ((nmlen == 1) && (nm[0] == '.'))) {
131d62bc4byz		*vpp = SDEVTOV(ddv);
132d62bc4byz		VN_HOLD(*vpp);
133d62bc4byz		return (0);
134d62bc4byz	}
135d62bc4byz
136d62bc4byz	/*
137d62bc4byz	 * .., return the parent directory
138d62bc4byz	 */
139d62bc4byz	if ((nmlen == 2) && (strcmp(nm, "..") == 0)) {
140d62bc4byz		*vpp = SDEVTOV(ddv->sdev_dotdot);
141d62bc4byz		VN_HOLD(*vpp);
142d62bc4byz		return (0);
143d62bc4byz	}
144d62bc4byz
145d62bc4byz	rw_enter(&ddv->sdev_contents, RW_WRITER);
146d62bc4byz
147d62bc4byz	/*
148d62bc4byz	 * directory cache lookup:
149d62bc4byz	 */
150d62bc4byz	if ((dv = sdev_cache_lookup(ddv, nm)) != NULL) {
1519e5aa9dRobert Mustacchi		ASSERT(dv->sdev_state == SDEV_READY);
1529e5aa9dRobert Mustacchi		if (!(dv->sdev_flags & SDEV_ATTR_INVALID))
1539e5aa9dRobert Mustacchi			goto found;
154d62bc4byz	}
155d62bc4byz
156d62bc4byz	/*
157d62bc4byz	 * ZOMBIED parent does not allow new node creation, bail out early.
158d62bc4byz	 */
159d62bc4byz	if (ddv->sdev_state == SDEV_ZOMBIE)
160d62bc4byz		goto failed;
161d62bc4byz
162d62bc4byz	error = devnet_create_rvp(nm, &vattr, &ddh);
163d62bc4byz	if (error != 0)
164d62bc4byz		goto failed;
165d62bc4byz
166d62bc4byz	error = sdev_mknode(ddv, nm, &dv, &vattr, NULL, NULL, cred, SDEV_READY);
167d62bc4byz	if (error != 0) {
168d62bc4byz		dls_devnet_close(ddh);
169d62bc4byz		goto failed;
170d62bc4byz	}
171d62bc4byz
172d62bc4byz	ASSERT(dv != NULL);
173d62bc4byz
174d62bc4byz	rw_enter(&dv->sdev_contents, RW_WRITER);
175d62bc4byz	if (dv->sdev_flags & SDEV_ATTR_INVALID) {
176d62bc4byz		/*
177d62bc4byz		 * SDEV_ATTR_INVALID means that this device has been
178d62bc4byz		 * detached, and its dev_t might've been changed too.
179d62bc4byz		 * Therefore, sdev_node's 'vattr' needs to be updated.
180d62bc4byz		 */
181d62bc4byz		SDEVTOV(dv)->v_rdev = vattr.va_rdev;
182d62bc4byz		ASSERT(dv->sdev_attr != NULL);
183d62bc4byz		dv->sdev_attr->va_rdev = vattr.va_rdev;
184d62bc4byz		dv->sdev_flags &= ~SDEV_ATTR_INVALID;
185d62bc4byz	}
186d62bc4byz	ASSERT(dv->sdev_private == NULL);
187d62bc4byz	dv->sdev_private = ddh;
188d62bc4byz	rw_exit(&dv->sdev_contents);
189d62bc4byz
190d62bc4byzfound:
191d62bc4byz	ASSERT(SDEV_HELD(dv));
192d62bc4byz	rw_exit(&ddv->sdev_contents);
193d62bc4byz	return (sdev_to_vp(dv, vpp));
194d62bc4byz
195d62bc4byzfailed:
196d62bc4byz	rw_exit(&ddv->sdev_contents);
197d62bc4byz
198d62bc4byz	if (dv != NULL)
199d62bc4byz		SDEV_RELE(dv);
200d62bc4byz
201d62bc4byz	*vpp = NULL;
202d62bc4byz	return (error);
203d62bc4byz}
204d62bc4byz
205d62bc4byzstatic int
2062b24ab6Sebastien Roydevnet_filldir_datalink(datalink_id_t linkid, void *arg)
207d62bc4byz{
2082b24ab6Sebastien Roy	struct sdev_node	*ddv = arg;
2092b24ab6Sebastien Roy	struct vattr		vattr;
2102b24ab6Sebastien Roy	struct sdev_node	*dv;
2112b24ab6Sebastien Roy	dls_dl_handle_t		ddh = NULL;
2122b24ab6Sebastien Roy	char			link[MAXLINKNAMELEN];
213d62bc4byz
214