xref: /illumos-gate/usr/src/uts/common/io/dld/dld_drv.c (revision eae72b5b807baa9116e64502cbb278edf15f3146)
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 /*
22d62bc4baSyz  * Copyright 2008 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  * Data-Link Driver
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include	<sys/conf.h>
31210db224Sericheng #include	<sys/mkdev.h>
327c478bd9Sstevel@tonic-gate #include	<sys/modctl.h>
33210db224Sericheng #include	<sys/stat.h>
34d62bc4baSyz #include	<sys/vlan.h>
353fd94f8cSam #include	<sys/mac.h>
367c478bd9Sstevel@tonic-gate #include	<sys/dld_impl.h>
37210db224Sericheng #include	<sys/dls_impl.h>
38d62bc4baSyz #include	<sys/softmac.h>
39f4b3ec61Sdh #include 	<sys/vlan.h>
40*eae72b5bSSebastien Roy #include	<sys/policy.h>
41210db224Sericheng #include	<inet/common.h>
42210db224Sericheng 
437c478bd9Sstevel@tonic-gate static void	drv_init(void);
447c478bd9Sstevel@tonic-gate static int	drv_fini(void);
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate static int	drv_getinfo(dev_info_t	*, ddi_info_cmd_t, void *, void **);
477c478bd9Sstevel@tonic-gate static int	drv_attach(dev_info_t *, ddi_attach_cmd_t);
487c478bd9Sstevel@tonic-gate static int	drv_detach(dev_info_t *, ddi_detach_cmd_t);
497c478bd9Sstevel@tonic-gate 
500ba2cbe9Sxc /*
510ba2cbe9Sxc  * Secure objects declarations
520ba2cbe9Sxc  */
530ba2cbe9Sxc #define	SECOBJ_WEP_HASHSZ	67
540ba2cbe9Sxc static krwlock_t	drv_secobj_lock;
550ba2cbe9Sxc static kmem_cache_t	*drv_secobj_cachep;
560ba2cbe9Sxc static mod_hash_t	*drv_secobj_hash;
570ba2cbe9Sxc static void		drv_secobj_init(void);
580ba2cbe9Sxc static void		drv_secobj_fini(void);
593bc21d0aSAruna Ramakrishna - Sun Microsystems static int		drv_ioc_setap(datalink_id_t, struct dlautopush *);
603bc21d0aSAruna Ramakrishna - Sun Microsystems static int		drv_ioc_getap(datalink_id_t, struct dlautopush *);
613bc21d0aSAruna Ramakrishna - Sun Microsystems static int		drv_ioc_clrap(datalink_id_t);
620ba2cbe9Sxc 
63*eae72b5bSSebastien Roy 
64210db224Sericheng /*
65210db224Sericheng  * The following entry points are private to dld and are used for control
66210db224Sericheng  * operations only. The entry points exported to mac drivers are defined
67210db224Sericheng  * in dld_str.c. Refer to the comment on top of dld_str.c for details.
68210db224Sericheng  */
69*eae72b5bSSebastien Roy static int	drv_open(dev_t *, int, int, cred_t *);
70*eae72b5bSSebastien Roy static int	drv_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
717c478bd9Sstevel@tonic-gate 
72*eae72b5bSSebastien Roy static dev_info_t	*dld_dip;	/* dev_info_t for the driver */
73*eae72b5bSSebastien Roy uint32_t		dld_opt = 0;	/* Global options */
747c478bd9Sstevel@tonic-gate 
75d62bc4baSyz #define	NAUTOPUSH 32
76d62bc4baSyz static mod_hash_t *dld_ap_hashp;
77d62bc4baSyz static krwlock_t dld_ap_hash_lock;
78d62bc4baSyz 
79*eae72b5bSSebastien Roy static struct cb_ops drv_cb_ops = {
80*eae72b5bSSebastien Roy 	drv_open,		/* open */
81*eae72b5bSSebastien Roy 	nulldev,		/* close */
82*eae72b5bSSebastien Roy 	nulldev,		/* strategy */
83*eae72b5bSSebastien Roy 	nulldev,		/* print */
84*eae72b5bSSebastien Roy 	nodev,			/* dump */
85*eae72b5bSSebastien Roy 	nodev,			/* read */
86*eae72b5bSSebastien Roy 	nodev,			/* write */
87*eae72b5bSSebastien Roy 	drv_ioctl,		/* ioctl */
88*eae72b5bSSebastien Roy 	nodev,			/* devmap */
89*eae72b5bSSebastien Roy 	nodev,			/* mmap */
90*eae72b5bSSebastien Roy 	nodev,			/* segmap */
91*eae72b5bSSebastien Roy 	nochpoll,		/* poll */
92*eae72b5bSSebastien Roy 	ddi_prop_op,		/* cb_prop_op */
93*eae72b5bSSebastien Roy 	0,			/* streamtab  */
94*eae72b5bSSebastien Roy 	D_MP			/* Driver compatibility flag */
957c478bd9Sstevel@tonic-gate };
967c478bd9Sstevel@tonic-gate 
97*eae72b5bSSebastien Roy static struct dev_ops drv_ops = {
98*eae72b5bSSebastien Roy 	DEVO_REV,		/* devo_rev */
99*eae72b5bSSebastien Roy 	0,			/* refcnt */
100*eae72b5bSSebastien Roy 	drv_getinfo,		/* get_dev_info */
101*eae72b5bSSebastien Roy 	nulldev,		/* identify */
102*eae72b5bSSebastien Roy 	nulldev,		/* probe */
103*eae72b5bSSebastien Roy 	drv_attach,		/* attach */
104*eae72b5bSSebastien Roy 	drv_detach,		/* detach */
105*eae72b5bSSebastien Roy 	nodev,			/* reset */
106*eae72b5bSSebastien Roy 	&drv_cb_ops,		/* driver operations */
107*eae72b5bSSebastien Roy 	NULL,			/* bus operations */
108*eae72b5bSSebastien Roy 	nodev			/* dev power */
1097c478bd9Sstevel@tonic-gate };
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate static	struct modldrv		drv_modldrv = {
1157c478bd9Sstevel@tonic-gate 	&mod_driverops,
1167c478bd9Sstevel@tonic-gate 	DLD_INFO,
1177c478bd9Sstevel@tonic-gate 	&drv_ops
1187c478bd9Sstevel@tonic-gate };
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate static	struct modlinkage	drv_modlinkage = {
1217c478bd9Sstevel@tonic-gate 	MODREV_1,
1227c478bd9Sstevel@tonic-gate 	&drv_modldrv,
1237c478bd9Sstevel@tonic-gate 	NULL
1247c478bd9Sstevel@tonic-gate };
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate int
1277c478bd9Sstevel@tonic-gate _init(void)
1287c478bd9Sstevel@tonic-gate {
129*eae72b5bSSebastien Roy 	return (mod_install(&drv_modlinkage));
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate int
1337c478bd9Sstevel@tonic-gate _fini(void)
1347c478bd9Sstevel@tonic-gate {
135*eae72b5bSSebastien Roy 	return (mod_remove(&drv_modlinkage));
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate int
1397c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	return (mod_info(&drv_modlinkage, modinfop));
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /*
145210db224Sericheng  * Initialize component modules.
1467c478bd9Sstevel@tonic-gate  */
1477c478bd9Sstevel@tonic-gate static void
1487c478bd9Sstevel@tonic-gate drv_init(void)
1497c478bd9Sstevel@tonic-gate {
1500ba2cbe9Sxc 	drv_secobj_init();
1517c478bd9Sstevel@tonic-gate 	dld_str_init();
152d62bc4baSyz 	/*
153d62bc4baSyz 	 * Create a hash table for autopush configuration.
154d62bc4baSyz 	 */
155d62bc4baSyz 	dld_ap_hashp = mod_hash_create_idhash("dld_autopush_hash",
156d62bc4baSyz 	    NAUTOPUSH, mod_hash_null_valdtor);
157d62bc4baSyz 
158d62bc4baSyz 	ASSERT(dld_ap_hashp != NULL);
159d62bc4baSyz 	rw_init(&dld_ap_hash_lock, NULL, RW_DRIVER, NULL);
160d62bc4baSyz }
161d62bc4baSyz 
162d62bc4baSyz /* ARGSUSED */
163d62bc4baSyz static uint_t
164d62bc4baSyz drv_ap_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
165d62bc4baSyz {
166d62bc4baSyz 	boolean_t *pexist = arg;
167d62bc4baSyz 
168d62bc4baSyz 	*pexist = B_TRUE;
169d62bc4baSyz 	return (MH_WALK_TERMINATE);
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate static int
1737c478bd9Sstevel@tonic-gate drv_fini(void)
1747c478bd9Sstevel@tonic-gate {
175d62bc4baSyz 	int		err;
176d62bc4baSyz 	boolean_t	exist = B_FALSE;
177d62bc4baSyz 
178d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_READER);
179d62bc4baSyz 	mod_hash_walk(dld_ap_hashp, drv_ap_exist, &exist);
180d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
181d62bc4baSyz 
182d62bc4baSyz 	if (exist)
183d62bc4baSyz 		return (EBUSY);
1847c478bd9Sstevel@tonic-gate 
185210db224Sericheng 	if ((err = dld_str_fini()) != 0)
1867c478bd9Sstevel@tonic-gate 		return (err);
1877c478bd9Sstevel@tonic-gate 
1880ba2cbe9Sxc 	drv_secobj_fini();
189d62bc4baSyz 	mod_hash_destroy_idhash(dld_ap_hashp);
190d62bc4baSyz 	rw_destroy(&dld_ap_hash_lock);
1917c478bd9Sstevel@tonic-gate 	return (0);
1927c478bd9Sstevel@tonic-gate }
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate /*
1957c478bd9Sstevel@tonic-gate  * devo_getinfo: getinfo(9e)
1967c478bd9Sstevel@tonic-gate  */
1977c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1987c478bd9Sstevel@tonic-gate static int
1997c478bd9Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
2007c478bd9Sstevel@tonic-gate {
2017c478bd9Sstevel@tonic-gate 	if (dld_dip == NULL)
2027c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	switch (cmd) {
2057c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
206*eae72b5bSSebastien Roy 		*resp = 0;
2077c478bd9Sstevel@tonic-gate 		break;
2087c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
209*eae72b5bSSebastien Roy 		*resp = dld_dip;
2107c478bd9Sstevel@tonic-gate 		break;
2117c478bd9Sstevel@tonic-gate 	default:
2127c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * Check properties to set options. (See dld.h for property definitions).
2207c478bd9Sstevel@tonic-gate  */
2217c478bd9Sstevel@tonic-gate static void
2227c478bd9Sstevel@tonic-gate drv_set_opt(dev_info_t *dip)
2237c478bd9Sstevel@tonic-gate {
2247c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2257c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_FASTPATH, 0) != 0) {
2267c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_FASTPATH;
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2307c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_POLL, 0) != 0) {
2317c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_POLL;
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2357c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_ZEROCOPY, 0) != 0) {
2367c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_ZEROCOPY;
2377c478bd9Sstevel@tonic-gate 	}
2389c175129Sja 
2399c175129Sja 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2409c175129Sja 	    DLD_PROP_NO_SOFTRING, 0) != 0) {
2419c175129Sja 		dld_opt |= DLD_OPT_NO_SOFTRING;
2429c175129Sja 	}
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate /*
2467c478bd9Sstevel@tonic-gate  * devo_attach: attach(9e)
2477c478bd9Sstevel@tonic-gate  */
2487c478bd9Sstevel@tonic-gate static int
2497c478bd9Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2507c478bd9Sstevel@tonic-gate {
2517c478bd9Sstevel@tonic-gate 	if (cmd != DDI_ATTACH)
2527c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	ASSERT(ddi_get_instance(dip) == 0);
255*eae72b5bSSebastien Roy 	drv_init();
2567c478bd9Sstevel@tonic-gate 	drv_set_opt(dip);
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	/*
2597c478bd9Sstevel@tonic-gate 	 * Create control node. DLPI provider nodes will be created on demand.
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR,
2627c478bd9Sstevel@tonic-gate 	    DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS)
2637c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	dld_dip = dip;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	/*
2687c478bd9Sstevel@tonic-gate 	 * Log the fact that the driver is now attached.
2697c478bd9Sstevel@tonic-gate 	 */
2707c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
2717c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate /*
2757c478bd9Sstevel@tonic-gate  * devo_detach: detach(9e)
2767c478bd9Sstevel@tonic-gate  */
2777c478bd9Sstevel@tonic-gate static int
2787c478bd9Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
2817c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	ASSERT(dld_dip == dip);
284*eae72b5bSSebastien Roy 	if (drv_fini() != 0)
285*eae72b5bSSebastien Roy 		return (DDI_FAILURE);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	/*
2887c478bd9Sstevel@tonic-gate 	 * Remove the control node.
2897c478bd9Sstevel@tonic-gate 	 */
2907c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME);
2917c478bd9Sstevel@tonic-gate 	dld_dip = NULL;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2947c478bd9Sstevel@tonic-gate }
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
297210db224Sericheng  * dld control node open procedure.
2987c478bd9Sstevel@tonic-gate  */
2997c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3007c478bd9Sstevel@tonic-gate static int
301*eae72b5bSSebastien Roy drv_open(dev_t *devp, int flag, int sflag, cred_t *credp)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate 	/*
304*eae72b5bSSebastien Roy 	 * Only the control node can be opened.
3057c478bd9Sstevel@tonic-gate 	 */
306*eae72b5bSSebastien Roy 	if (getminor(*devp) != DLD_CONTROL_MINOR)
307*eae72b5bSSebastien Roy 		return (ENODEV);
3087c478bd9Sstevel@tonic-gate 	return (0);
3097c478bd9Sstevel@tonic-gate }
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate /*
312d62bc4baSyz  * DLDIOC_ATTR
3137c478bd9Sstevel@tonic-gate  */
314*eae72b5bSSebastien Roy /* ARGSUSED */
315*eae72b5bSSebastien Roy static int
316*eae72b5bSSebastien Roy drv_ioc_attr(void *karg, intptr_t arg, int mode, cred_t *cred)
3177c478bd9Sstevel@tonic-gate {
318*eae72b5bSSebastien Roy 	dld_ioc_attr_t		*diap = karg;
319d62bc4baSyz 	dls_dl_handle_t		dlh;
320d62bc4baSyz 	dls_vlan_t		*dvp;
321d62bc4baSyz 	int			err;
322210db224Sericheng 
323d62bc4baSyz 	if ((err = dls_devnet_hold_tmp(diap->dia_linkid, &dlh)) != 0)
324*eae72b5bSSebastien Roy 		return (err);
325210db224Sericheng 
326d62bc4baSyz 	if ((err = dls_vlan_hold(dls_devnet_mac(dlh),
327d62bc4baSyz 	    dls_devnet_vid(dlh), &dvp, B_FALSE, B_FALSE)) != 0) {
328d62bc4baSyz 		dls_devnet_rele_tmp(dlh);
329*eae72b5bSSebastien Roy 		return (err);
330d62bc4baSyz 	}
331e7801d59Ssowmini 	mac_sdu_get(dvp->dv_dlp->dl_mh, NULL, &diap->dia_max_sdu);
332210db224Sericheng 
333210db224Sericheng 	dls_vlan_rele(dvp);
334d62bc4baSyz 	dls_devnet_rele_tmp(dlh);
335d62bc4baSyz 
336*eae72b5bSSebastien Roy 	return (0);
337d62bc4baSyz }
338210db224Sericheng 
339d62bc4baSyz /*
340d62bc4baSyz  * DLDIOC_PHYS_ATTR
341d62bc4baSyz  */
342*eae72b5bSSebastien Roy /* ARGSUSED */
343*eae72b5bSSebastien Roy static int
344*eae72b5bSSebastien Roy drv_ioc_phys_attr(void *karg, intptr_t arg, int mode, cred_t *cred)
345d62bc4baSyz {
346*eae72b5bSSebastien Roy 	dld_ioc_phys_attr_t	*dipp = karg;
347d62bc4baSyz 	int			err;
348d62bc4baSyz 	dls_dl_handle_t		dlh;
349d62bc4baSyz 	dls_dev_handle_t	ddh;
350d62bc4baSyz 	dev_t			phydev;
351d62bc4baSyz 
352d62bc4baSyz 	/*
353d62bc4baSyz 	 * Every physical link should have its physical dev_t kept in the
354d62bc4baSyz 	 * daemon. If not, it is not a valid physical link.
355d62bc4baSyz 	 */
356*eae72b5bSSebastien Roy 	if (dls_mgmt_get_phydev(dipp->dip_linkid, &phydev) != 0)
357*eae72b5bSSebastien Roy 		return (EINVAL);
358d62bc4baSyz 
359d62bc4baSyz 	/*
360d62bc4baSyz 	 * Although this is a valid physical link, it might already be removed
361d62bc4baSyz 	 * by DR or during system shutdown. softmac_hold_device() would return
362d62bc4baSyz 	 * ENOENT in this case.
363d62bc4baSyz 	 */
364d62bc4baSyz 	if ((err = softmac_hold_device(phydev, &ddh)) != 0)
365*eae72b5bSSebastien Roy 		return (err);
366d62bc4baSyz 
367d62bc4baSyz 	if (dls_devnet_hold_tmp(dipp->dip_linkid, &dlh) != 0) {
368210db224Sericheng 		/*
369d62bc4baSyz 		 * Although this is an active physical link, its link type is
370d62bc4baSyz 		 * not supported by GLDv3, and therefore it does not have
371d62bc4baSyz 		 * vanity naming support.
372210db224Sericheng 		 */
373d62bc4baSyz 		dipp->dip_novanity = B_TRUE;
374d62bc4baSyz 	} else {
375d62bc4baSyz 		dipp->dip_novanity = B_FALSE;
376d62bc4baSyz 		dls_devnet_rele_tmp(dlh);
377210db224Sericheng 	}
378d62bc4baSyz 	/*
379d62bc4baSyz 	 * Get the physical device name from the major number and the instance
380d62bc4baSyz 	 * number derived from phydev.
381d62bc4baSyz 	 */
382d62bc4baSyz 	(void) snprintf(dipp->dip_dev, MAXLINKNAMELEN, "%s%d",
383d62bc4baSyz 	    ddi_major_to_name(getmajor(phydev)), getminor(phydev) - 1);
384d62bc4baSyz 
385d62bc4baSyz 	softmac_rele_device(ddh);
386*eae72b5bSSebastien Roy 	return (0);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
389e7801d59Ssowmini /*
3903fd94f8cSam  * DLDIOC_SETPROP
391e7801d59Ssowmini  */
392*eae72b5bSSebastien Roy static int
393*eae72b5bSSebastien Roy drv_ioc_prop_common(dld_ioc_macprop_t *dipp, intptr_t arg, boolean_t set,
394*eae72b5bSSebastien Roy     int mode)
395e7801d59Ssowmini {
396*eae72b5bSSebastien Roy 	int		err = EINVAL;
397*eae72b5bSSebastien Roy 	size_t		dsize;
398*eae72b5bSSebastien Roy 	dld_ioc_macprop_t	*kdipp;
399*eae72b5bSSebastien Roy 	dls_dl_handle_t		dlh;
400e7801d59Ssowmini 	dls_vlan_t		*dvp;
401e7801d59Ssowmini 	datalink_id_t 		linkid;
402e7801d59Ssowmini 	mac_prop_t		macprop;
4033bc21d0aSAruna Ramakrishna - Sun Microsystems 	uchar_t			*cp;
4043bc21d0aSAruna Ramakrishna - Sun Microsystems 	struct dlautopush	*dlap;
4053bc21d0aSAruna Ramakrishna - Sun Microsystems 	dld_ioc_zid_t		*dzp;
406e7801d59Ssowmini 
407*eae72b5bSSebastien Roy 	/*
408*eae72b5bSSebastien Roy 	 * We only use pr_valsize from dipp, as the caller only did a
409*eae72b5bSSebastien Roy 	 * copyin() for sizeof (dld_ioc_prop_t), which doesn't cover
410*eae72b5bSSebastien Roy 	 * the property data.  We copyin the full dld_ioc_prop_t
411*eae72b5bSSebastien Roy 	 * including the data into kdipp down below.
412*eae72b5bSSebastien Roy 	 */
4133fd94f8cSam 	dsize = sizeof (dld_ioc_macprop_t) + dipp->pr_valsize - 1;
414*eae72b5bSSebastien Roy 	if (dsize < dipp->pr_valsize)
415*eae72b5bSSebastien Roy 		return (EINVAL);
416*eae72b5bSSebastien Roy 
417*eae72b5bSSebastien Roy 	/*
418*eae72b5bSSebastien Roy 	 * The property data is variable size, so we need to allocate
419*eae72b5bSSebastien Roy 	 * a buffer for kernel use as this data was not part of the
420*eae72b5bSSebastien Roy 	 * dipp allocation and copyin() done by the framework.
421*eae72b5bSSebastien Roy 	 */
422*eae72b5bSSebastien Roy 	if ((kdipp = kmem_alloc(dsize, KM_NOSLEEP)) == NULL)
423*eae72b5bSSebastien Roy 		return (ENOMEM);
424*eae72b5bSSebastien Roy 	if (ddi_copyin((void *)arg, kdipp, dsize, mode) != 0) {
425*eae72b5bSSebastien Roy 		err = EFAULT;
426e7801d59Ssowmini 		goto done;
427*eae72b5bSSebastien Roy 	}
428e7801d59Ssowmini 
429*eae72b5bSSebastien Roy 	linkid = kdipp->pr_linkid;
430e7801d59Ssowmini 
4313bc21d0aSAruna Ramakrishna - Sun Microsystems 	switch (dipp->pr_num) {
4323bc21d0aSAruna Ramakrishna - Sun Microsystems 	case MAC_PROP_ZONE:
4333bc21d0aSAruna Ramakrishna - Sun Microsystems 		if (set) {
434*eae72b5bSSebastien Roy 			dzp = (dld_ioc_zid_t *)kdipp->pr_val;
4353bc21d0aSAruna Ramakrishna - Sun Microsystems 			err = dls_devnet_setzid(dzp->diz_link, dzp->diz_zid);
4363bc21d0aSAruna Ramakrishna - Sun Microsystems 			goto done;
4373bc21d0aSAruna Ramakrishna - Sun Microsystems 		} else {
438*eae72b5bSSebastien Roy 			cp = (uchar_t *)kdipp->pr_val;
4393bc21d0aSAruna Ramakrishna - Sun Microsystems 			err = dls_devnet_getzid(linkid, (zoneid_t *)cp);
4403bc21d0aSAruna Ramakrishna - Sun Microsystems 			goto done;
4413bc21d0aSAruna Ramakrishna - Sun Microsystems 		}
4423bc21d0aSAruna Ramakrishna - Sun Microsystems 	case MAC_PROP_AUTOPUSH:
4433bc21d0aSAruna Ramakrishna - Sun Microsystems 		if (set) {
4443bc21d0aSAruna Ramakrishna - Sun Microsystems 			if (dipp->pr_valsize != 0) {
445*eae72b5bSSebastien Roy 				dlap = (struct dlautopush *)kdipp->pr_val;
4463bc21d0aSAruna Ramakrishna - Sun Microsystems 				err = drv_ioc_setap(linkid, dlap);
4473bc21d0aSAruna Ramakrishna - Sun Microsystems 				goto done;
4483bc21d0aSAruna Ramakrishna - Sun Microsystems 			} else {
4493bc21d0aSAruna Ramakrishna - Sun Microsystems 				err = drv_ioc_clrap(linkid);
4503bc21d0aSAruna Ramakrishna - Sun Microsystems 				goto done;
4513bc21d0aSAruna Ramakrishna - Sun Microsystems 			}
4523bc21d0aSAruna Ramakrishna - Sun Microsystems 		} else {
453*eae72b5bSSebastien Roy 			dlap = (struct dlautopush *)kdipp->pr_val;
4543bc21d0aSAruna Ramakrishna - Sun Microsystems 			err = drv_ioc_getap(linkid, dlap);
4553bc21d0aSAruna Ramakrishna - Sun Microsystems 			goto done;
4563bc21d0aSAruna Ramakrishna - Sun Microsystems 		}
4573bc21d0aSAruna Ramakrishna - Sun Microsystems 
4583bc21d0aSAruna Ramakrishna - Sun Microsystems 	default:
4593bc21d0aSAruna Ramakrishna - Sun Microsystems 		break;
4603bc21d0aSAruna Ramakrishna - Sun Microsystems 	}
4613bc21d0aSAruna Ramakrishna - Sun Microsystems 
462e7801d59Ssowmini 	if ((err = dls_devnet_hold_tmp(linkid, &dlh)) != 0)
463e7801d59Ssowmini 		goto done;
464e7801d59Ssowmini 
465e7801d59Ssowmini 	if ((err = dls_vlan_hold(dls_devnet_mac(dlh),
466e7801d59Ssowmini 	    dls_devnet_vid(dlh), &dvp, B_FALSE, B_FALSE)) != 0) {
467e7801d59Ssowmini 		dls_devnet_rele_tmp(dlh);
468e7801d59Ssowmini 		goto done;
469e7801d59Ssowmini 	}
470e7801d59Ssowmini 
471*eae72b5bSSebastien Roy 	macprop.mp_name = kdipp->pr_name;
472*eae72b5bSSebastien Roy 	macprop.mp_id = kdipp->pr_num;
473*eae72b5bSSebastien Roy 	macprop.mp_flags = kdipp->pr_flags;
474e7801d59Ssowmini 
475*eae72b5bSSebastien Roy 	if (set) {
476e7801d59Ssowmini 		err = mac_set_prop(dvp->dv_dlp->dl_mh, &macprop,
477*eae72b5bSSebastien Roy 		    kdipp->pr_val, kdipp->pr_valsize);
478*eae72b5bSSebastien Roy 	} else {
479e7801d59Ssowmini 		err = mac_get_prop(dvp->dv_dlp->dl_mh, &macprop,
480*eae72b5bSSebastien Roy 		    kdipp->pr_val, kdipp->pr_valsize);
481*eae72b5bSSebastien Roy 	}
482e7801d59Ssowmini 
483e7801d59Ssowmini 	dls_vlan_rele(dvp);
484e7801d59Ssowmini 	dls_devnet_rele_tmp(dlh);
485e7801d59Ssowmini done:
486*eae72b5bSSebastien Roy 	if (!set && err == 0 &&
487*eae72b5bSSebastien Roy 	    ddi_copyout(kdipp, (void *)arg, dsize, mode) != 0)
488*eae72b5bSSebastien Roy 		err = EFAULT;
489*eae72b5bSSebastien Roy 	kmem_free(kdipp, dsize);
490*eae72b5bSSebastien Roy 	return (err);
491e7801d59Ssowmini }
492e7801d59Ssowmini 
493*eae72b5bSSebastien Roy /* ARGSUSED */
494*eae72b5bSSebastien Roy static int
495*eae72b5bSSebastien Roy drv_ioc_setprop(void *karg, intptr_t arg, int mode, cred_t *cred)
496e7801d59Ssowmini {
497*eae72b5bSSebastien Roy 	return (drv_ioc_prop_common(karg, arg, B_TRUE, mode));
498e7801d59Ssowmini }
499e7801d59Ssowmini 
500*eae72b5bSSebastien Roy /* ARGSUSED */
501*eae72b5bSSebastien Roy static int
502*eae72b5bSSebastien Roy drv_ioc_getprop(void *karg, intptr_t arg, int mode, cred_t *cred)
503e7801d59Ssowmini {
504*eae72b5bSSebastien Roy 	return (drv_ioc_prop_common(karg, arg, B_FALSE, mode));
505e7801d59Ssowmini }
506e7801d59Ssowmini 
5077c478bd9Sstevel@tonic-gate /*
508d62bc4baSyz  * DLDIOC_CREATE_VLAN
5097c478bd9Sstevel@tonic-gate  */
510*eae72b5bSSebastien Roy /* ARGSUSED */
511*eae72b5bSSebastien Roy static int
512*eae72b5bSSebastien Roy drv_ioc_create_vlan(void *karg, intptr_t arg, int mode, cred_t *cred)
513210db224Sericheng {
514*eae72b5bSSebastien Roy 	dld_ioc_create_vlan_t	*dicp = karg;
515d62bc4baSyz 
516*eae72b5bSSebastien Roy 	return (dls_devnet_create_vlan(dicp->dic_vlanid, dicp->dic_linkid,
517*eae72b5bSSebastien Roy 	    dicp->dic_vid, dicp->dic_force));
518210db224Sericheng }
519210db224Sericheng 
520d62bc4baSyz /*
521d62bc4baSyz  * DLDIOC_DELETE_VLAN
522d62bc4baSyz  */
523*eae72b5bSSebastien Roy /* ARGSUSED */
524*eae72b5bSSebastien Roy static int
525*eae72b5bSSebastien Roy drv_ioc_delete_vlan(void *karg, intptr_t arg, int mode, cred_t *cred)
5267c478bd9Sstevel@tonic-gate {
527*eae72b5bSSebastien Roy 	dld_ioc_delete_vlan_t	*didp = karg;
528d62bc4baSyz 
529*eae72b5bSSebastien Roy 	return (dls_devnet_destroy_vlan(didp->did_linkid));
530d62bc4baSyz }
531d62bc4baSyz 
532d62bc4baSyz /*
533d62bc4baSyz  * DLDIOC_VLAN_ATTR
534d62bc4baSyz  */
535*eae72b5bSSebastien Roy /* ARGSUSED */
536*eae72b5bSSebastien Roy static int
537*eae72b5bSSebastien Roy drv_ioc_vlan_attr(void *karg, intptr_t arg, int mode, cred_t *cred)
538d62bc4baSyz {
539*eae72b5bSSebastien Roy 	dld_ioc_vlan_attr_t	*divp = karg;
540d62bc4baSyz 	dls_dl_handle_t		dlh;
541d62bc4baSyz 	uint16_t		vid;
542d62bc4baSyz 	dls_vlan_t		*dvp;
543d62bc4baSyz 	int			err;
5447c478bd9Sstevel@tonic-gate 
545d62bc4baSyz 	/*
546d62bc4baSyz 	 * Hold this link to prevent it from being deleted.
547d62bc4baSyz 	 */
548*eae72b5bSSebastien Roy 	if ((err = dls_devnet_hold_tmp(divp->div_vlanid, &dlh)) != 0)
549*eae72b5bSSebastien Roy 		return (err);
550210db224Sericheng 
551d62bc4baSyz 	if ((vid = dls_devnet_vid(dlh)) == VLAN_ID_NONE) {
552d62bc4baSyz 		dls_devnet_rele_tmp(dlh);
553*eae72b5bSSebastien Roy 		return (EINVAL);
554d62bc4baSyz 	}
555d62bc4baSyz 
556d62bc4baSyz 	err = dls_vlan_hold(dls_devnet_mac(dlh), vid, &dvp, B_FALSE, B_FALSE);
557d62bc4baSyz 	if (err != 0) {
558d62bc4baSyz 		dls_devnet_rele_tmp(dlh);
559*eae72b5bSSebastien Roy 		return (err);
560d62bc4baSyz 	}
561d62bc4baSyz 
562d62bc4baSyz 	divp->div_linkid = dls_devnet_linkid(dlh);
563d62bc4baSyz 	divp->div_implicit = !dls_devnet_is_explicit(dlh);
564d62bc4baSyz 	divp->div_vid = vid;
565d62bc4baSyz 	divp->div_force = dvp->dv_force;
566d62bc4baSyz 
567d62bc4baSyz 	dls_vlan_rele(dvp);
568d62bc4baSyz 	dls_devnet_rele_tmp(dlh);
569*eae72b5bSSebastien Roy 	return (0);
570210db224Sericheng }
571210db224Sericheng 
572f4b3ec61Sdh /*
573d62bc4baSyz  * DLDIOC_RENAME.
574d62bc4baSyz  *
575d62bc4baSyz  * This function handles two cases of link renaming. See more in comments above
576d62bc4baSyz  * dls_datalink_rename().
577f4b3ec61Sdh  */
578*eae72b5bSSebastien Roy /* ARGSUSED */
579*eae72b5bSSebastien Roy static int
580*eae72b5bSSebastien Roy drv_ioc_rename(void *karg, intptr_t arg, int mode, cred_t *cred)
581f4b3ec61Sdh {
582*eae72b5bSSebastien Roy 	dld_ioc_rename_t	*dir = karg;
583d62bc4baSyz 	mod_hash_key_t		key;
584d62bc4baSyz 	mod_hash_val_t		val;
585d62bc4baSyz 	int			err;
586d62bc4baSyz 
587d62bc4baSyz 	if ((err = dls_devnet_rename(dir->dir_linkid1, dir->dir_linkid2,
588*eae72b5bSSebastien Roy 	    dir->dir_link)) != 0)
589*eae72b5bSSebastien Roy 		return (err);
590d62bc4baSyz 
591d62bc4baSyz 	if (dir->dir_linkid2 == DATALINK_INVALID_LINKID)
592*eae72b5bSSebastien Roy 		return (0);
593d62bc4baSyz 
594d62bc4baSyz 	/*
595d62bc4baSyz 	 * if dir_linkid2 is not DATALINK_INVALID_LINKID, it means this
596d62bc4baSyz 	 * renaming request is to rename a valid physical link (dir_linkid1)
597d62bc4baSyz 	 * to a "removed" physical link (dir_linkid2, which is removed by DR
598d62bc4baSyz 	 * or during system shutdown). In this case, the link (specified by
599d62bc4baSyz 	 * dir_linkid1) would inherit all the configuration of dir_linkid2,
600d62bc4baSyz 	 * and dir_linkid1 and its configuration would be lost.
601d62bc4baSyz 	 *
602d62bc4baSyz 	 * Remove per-link autopush configuration of dir_linkid1 in this case.
603d62bc4baSyz 	 */
604d62bc4baSyz 	key = (mod_hash_key_t)(uintptr_t)dir->dir_linkid1;
605d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_WRITER);
606d62bc4baSyz 	if (mod_hash_find(dld_ap_hashp, key, &val) != 0) {
607d62bc4baSyz 		rw_exit(&dld_ap_hash_lock);
608*eae72b5bSSebastien Roy 		return (0);
609d62bc4baSyz 	}
610d62bc4baSyz 
611d62bc4baSyz 	VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0);
612d62bc4baSyz 	kmem_free(val, sizeof (dld_ap_t));
613d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
614*eae72b5bSSebastien Roy 	return (0);
615d62bc4baSyz }
616d62bc4baSyz 
6173bc21d0aSAruna Ramakrishna - Sun Microsystems static int
6183bc21d0aSAruna Ramakrishna - Sun Microsystems drv_ioc_setap(datalink_id_t linkid, struct dlautopush *dlap)
619d62bc4baSyz {
620d62bc4baSyz 	dld_ap_t	*dap;
621*eae72b5bSSebastien Roy 	int		i;
622d62bc4baSyz 	mod_hash_key_t	key;
623d62bc4baSyz 
624*eae72b5bSSebastien Roy 	if (dlap->dap_npush == 0 || dlap->dap_npush > MAXAPUSH)
625*eae72b5bSSebastien Roy 		return (EINVAL);
626f4b3ec61Sdh 
627789e0dbbSdh 	/*
628d62bc4baSyz 	 * Validate that the specified list of modules exist.
629789e0dbbSdh 	 */
6303bc21d0aSAruna Ramakrishna - Sun Microsystems 	for (i = 0; i < dlap->dap_npush; i++) {
631*eae72b5bSSebastien Roy 		if (fmodsw_find(dlap->dap_aplist[i], FMODSW_LOAD) == NULL)
632*eae72b5bSSebastien Roy 			return (EINVAL);
633d62bc4baSyz 	}
634d62bc4baSyz 
635*eae72b5bSSebastien Roy 
6363bc21d0aSAruna Ramakrishna - Sun Microsystems 	key = (mod_hash_key_t)(uintptr_t)linkid;
637789e0dbbSdh 
638d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_WRITER);
639d62bc4baSyz 	if (mod_hash_find(dld_ap_hashp, key, (mod_hash_val_t *)&dap) != 0) {
640d62bc4baSyz 		dap = kmem_zalloc(sizeof (dld_ap_t), KM_NOSLEEP);
641d62bc4baSyz 		if (dap == NULL) {
642d62bc4baSyz 			rw_exit(&dld_ap_hash_lock);
643*eae72b5bSSebastien Roy 			return (ENOMEM);
644d62bc4baSyz 		}
645d62bc4baSyz 
6463bc21d0aSAruna Ramakrishna - Sun Microsystems 		dap->da_linkid = linkid;
647*eae72b5bSSebastien Roy 		VERIFY(mod_hash_insert(dld_ap_hashp, key,
648*eae72b5bSSebastien Roy 		    (mod_hash_val_t)dap) == 0);
649f4b3ec61Sdh 	}
650f4b3ec61Sdh 
651d62bc4baSyz 	/*
652d62bc4baSyz 	 * Update the configuration.
653d62bc4baSyz 	 */
6543bc21d0aSAruna Ramakrishna - Sun Microsystems 	dap->da_anchor = dlap->dap_anchor;
6553bc21d0aSAruna Ramakrishna - Sun Microsystems 	dap->da_npush = dlap->dap_npush;
6563bc21d0aSAruna Ramakrishna - Sun Microsystems 	for (i = 0; i < dlap->dap_npush; i++) {
6573bc21d0aSAruna Ramakrishna - Sun Microsystems 		(void) strlcpy(dap->da_aplist[i], dlap->dap_aplist[i],
658d62bc4baSyz 		    FMNAMESZ + 1);
659d62bc4baSyz 	}
660d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
661789e0dbbSdh 
6623bc21d0aSAruna Ramakrishna - Sun Microsystems 	return (0);
663d62bc4baSyz }
664d62bc4baSyz 
6653bc21d0aSAruna Ramakrishna - Sun Microsystems static int
6663bc21d0aSAruna Ramakrishna - Sun Microsystems drv_ioc_getap(datalink_id_t linkid, struct dlautopush *dlap)
667d62bc4baSyz {
668d62bc4baSyz 	dld_ap_t	*dap;
669*eae72b5bSSebastien Roy 	int		i;
670d62bc4baSyz 
671d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_READER);
672d62bc4baSyz 	if (mod_hash_find(dld_ap_hashp,
6733bc21d0aSAruna Ramakrishna - Sun Microsystems 	    (mod_hash_key_t)(uintptr_t)linkid,
674d62bc4baSyz 	    (mod_hash_val_t *)&dap) != 0) {
675d62bc4baSyz 		rw_exit(&dld_ap_hash_lock);
676*eae72b5bSSebastien Roy 		return (ENOENT);
677f595a68aSyz 	}
678d62bc4baSyz 
679d62bc4baSyz 	/*
680d62bc4baSyz 	 * Retrieve the configuration.
681d62bc4baSyz 	 */
6823bc21d0aSAruna Ramakrishna - Sun Microsystems 	dlap->dap_anchor = dap->da_anchor;
6833bc21d0aSAruna Ramakrishna - Sun Microsystems 	dlap->dap_npush = dap->da_npush;
684d62bc4baSyz 	for (i = 0; i < dap->da_npush; i++) {
6853bc21d0aSAruna Ramakrishna - Sun Microsystems 		(void) strlcpy(dlap->dap_aplist[i], dap->da_aplist[i],
686d62bc4baSyz 		    FMNAMESZ + 1);
687d62bc4baSyz 	}
688d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
689d62bc4baSyz 
6903bc21d0aSAruna Ramakrishna - Sun Microsystems 	return (0);
691f4b3ec61Sdh }
692f4b3ec61Sdh 
6933bc21d0aSAruna Ramakrishna - Sun Microsystems static int
6943bc21d0aSAruna Ramakrishna - Sun Microsystems drv_ioc_clrap(datalink_id_t linkid)
695f4b3ec61Sdh {
696d62bc4baSyz 	mod_hash_val_t	val;
697d62bc4baSyz 	mod_hash_key_t	key;
698f4b3ec61Sdh 
6993bc21d0aSAruna Ramakrishna - Sun Microsystems 	key = (mod_hash_key_t)(uintptr_t)linkid;
700f4b3ec61Sdh 
701d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_WRITER);
702d62bc4baSyz 	if (mod_hash_find(dld_ap_hashp, key, &val) != 0) {
703d62bc4baSyz 		rw_exit(&dld_ap_hash_lock);
7043bc21d0aSAruna Ramakrishna - Sun Microsystems 		return (0);
705f4b3ec61Sdh 	}
706f4b3ec61Sdh 
707d62bc4baSyz 	VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0);
708d62bc4baSyz 	kmem_free(val, sizeof (dld_ap_t));
709d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
7103bc21d0aSAruna Ramakrishna - Sun Microsystems 	return (0);
711f4b3ec61Sdh }
712f4b3ec61Sdh 
713f4b3ec61Sdh /*
714d62bc4baSyz  * DLDIOC_DOORSERVER
715f4b3ec61Sdh  */
716*eae72b5bSSebastien Roy /* ARGSUSED */
717*eae72b5bSSebastien Roy static int
718*eae72b5bSSebastien Roy drv_ioc_doorserver(void *karg, intptr_t arg, int mode, cred_t *cred)
719210db224Sericheng {
720*eae72b5bSSebastien Roy 	dld_ioc_door_t	*did = karg;
721210db224Sericheng 
722*eae72b5bSSebastien Roy 	return (dls_mgmt_door_set(did->did_start_door));
7237c478bd9Sstevel@tonic-gate }
7240ba2cbe9Sxc 
725d62bc4baSyz /*
726d62bc4baSyz  * Check for GLDv3 autopush information.  There are three cases:
727d62bc4baSyz  *
728d62bc4baSyz  *   1. If devp points to a GLDv3 datalink and it has autopush configuration,
729d62bc4baSyz  *	fill dlap in with that information and return 0.
730d62bc4baSyz  *
731d62bc4baSyz  *   2. If devp points to a GLDv3 datalink but it doesn't have autopush
732d62bc4baSyz  *	configuration, then replace devp with the physical device (if one
733d62bc4baSyz  *	exists) and return 1.  This allows stropen() to find the old-school
734d62bc4baSyz  *	per-driver autopush configuration.  (For softmac, the result is that
735d62bc4baSyz  *	the softmac dev_t is replaced with the legacy device's dev_t).
736d62bc4baSyz  *
737d62bc4baSyz  *   3. If neither of the above apply, don't touch the args and return -1.
738d62bc4baSyz  */
739d62bc4baSyz int
740d62bc4baSyz dld_autopush(dev_t *devp, struct dlautopush *dlap)
741d62bc4baSyz {
742d62bc4baSyz 	dld_ap_t	*dap;
743d62bc4baSyz 	datalink_id_t	linkid;
744d62bc4baSyz 	dev_t		phydev;
745d62bc4baSyz 
746d62bc4baSyz 	if (!GLDV3_DRV(getmajor(*devp)))
747d62bc4baSyz 		return (-1);
748d62bc4baSyz 
749d62bc4baSyz 	/*
750d62bc4baSyz 	 * Find the linkid by the link's dev_t.
751d62bc4baSyz 	 */
752d62bc4baSyz 	if (dls_devnet_dev2linkid(*devp, &linkid) != 0)
753d62bc4baSyz 		return (-1);
754d62bc4baSyz 
755d62bc4baSyz 	/*
756d62bc4baSyz 	 * Find the autopush configuration associated with the linkid.
757d62bc4baSyz 	 */
758d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_READER);
759d62bc4baSyz 	if (mod_hash_find(dld_ap_hashp, (mod_hash_key_t)(uintptr_t)linkid,
760d62bc4baSyz 	    (mod_hash_val_t *)&dap) == 0) {
761d62bc4baSyz 		*dlap = dap->da_ap;
762d62bc4baSyz 		rw_exit(&dld_ap_hash_lock);
763d62bc4baSyz 		return (0);
764d62bc4baSyz 	}
765d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
766d62bc4baSyz 
767d62bc4baSyz 	if (dls_devnet_phydev(linkid, &phydev) != 0)
768d62bc4baSyz 		return (-1);
769d62bc4baSyz 
770d62bc4baSyz 	*devp = phydev;
771d62bc4baSyz 	return (1);
772d62bc4baSyz }
773d62bc4baSyz 
7740ba2cbe9Sxc /*
7750ba2cbe9Sxc  * Secure objects implementation
7760ba2cbe9Sxc  */
7770ba2cbe9Sxc 
7780ba2cbe9Sxc /* ARGSUSED */
7790ba2cbe9Sxc static int
7800ba2cbe9Sxc drv_secobj_ctor(void *buf, void *arg, int kmflag)
7810ba2cbe9Sxc {
7820ba2cbe9Sxc 	bzero(buf, sizeof (dld_secobj_t));
7830ba2cbe9Sxc 	return (0);
7840ba2cbe9Sxc }
7850ba2cbe9Sxc 
7860ba2cbe9Sxc static void
7870ba2cbe9Sxc drv_secobj_init(void)
7880ba2cbe9Sxc {
7890ba2cbe9Sxc 	rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL);
7900ba2cbe9Sxc 	drv_secobj_cachep = kmem_cache_create("drv_secobj_cache",
7910ba2cbe9Sxc 	    sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL,
7920ba2cbe9Sxc 	    NULL, NULL, NULL, 0);
7930ba2cbe9Sxc 	drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash",
7940ba2cbe9Sxc 	    SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
7950ba2cbe9Sxc 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
7960ba2cbe9Sxc }
7970ba2cbe9Sxc 
7980ba2cbe9Sxc static void
7990ba2cbe9Sxc drv_secobj_fini(void)
8000ba2cbe9Sxc {
8010ba2cbe9Sxc 	mod_hash_destroy_hash(drv_secobj_hash);
8020ba2cbe9Sxc 	kmem_cache_destroy(drv_secobj_cachep);
8030ba2cbe9Sxc 	rw_destroy(&drv_secobj_lock);
8040ba2cbe9Sxc }
8050ba2cbe9Sxc 
806*eae72b5bSSebastien Roy /* ARGSUSED */
807*eae72b5bSSebastien Roy static int
808*eae72b5bSSebastien Roy drv_ioc_secobj_set(void *karg, intptr_t arg, int mode, cred_t *cred)
8090ba2cbe9Sxc {
810*eae72b5bSSebastien Roy 	dld_ioc_secobj_set_t	*ssp = karg;
8110ba2cbe9Sxc 	dld_secobj_t		*sobjp, *objp;
812*eae72b5bSSebastien Roy 	int			err;
8130ba2cbe9Sxc 
8140ba2cbe9Sxc 	sobjp = &ssp->ss_obj;
8150ba2cbe9Sxc 
816a399b765Szf 	if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP &&
817a399b765Szf 	    sobjp->so_class != DLD_SECOBJ_CLASS_WPA)
818*eae72b5bSSebastien Roy 		return (EINVAL);
8190ba2cbe9Sxc 
8200ba2cbe9Sxc 	if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' ||
8210ba2cbe9Sxc 	    sobjp->so_len > DLD_SECOBJ_VAL_MAX)
822*eae72b5bSSebastien Roy 		return (EINVAL);
8230ba2cbe9Sxc 
8240ba2cbe9Sxc 	rw_enter(&drv_secobj_lock, RW_WRITER);
8250ba2cbe9Sxc 	err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name,
8260ba2cbe9Sxc 	    (mod_hash_val_t *)&objp);
8270ba2cbe9Sxc 	if (err == 0) {
8280ba2cbe9Sxc 		if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) {
8290ba2cbe9Sxc 			rw_exit(&drv_secobj_lock);
830*eae72b5bSSebastien Roy 			return (EEXIST);
8310ba2cbe9Sxc 		}
8320ba2cbe9Sxc 	} else {
8330ba2cbe9Sxc 		ASSERT(err == MH_ERR_NOTFOUND);
8340ba2cbe9Sxc 		if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) {
8350ba2cbe9Sxc 			rw_exit(&drv_secobj_lock);
836*eae72b5bSSebastien Roy 			return (ENOENT);
8370ba2cbe9Sxc 		}
8380ba2cbe9Sxc 		objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP);
8390ba2cbe9Sxc 		(void) strlcpy(objp->so_name, sobjp->so_name,
8400ba2cbe9Sxc 		    DLD_SECOBJ_NAME_MAX);
8410ba2cbe9Sxc 
842*eae72b5bSSebastien Roy 		VERIFY(mod_hash_insert(drv_secobj_hash,
843*eae72b5bSSebastien Roy 		    (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp) == 0);
8440ba2cbe9Sxc 	}
8450ba2cbe9Sxc 	bcopy(sobjp->so_val, objp->so_val, sobjp->so_len);
8460ba2cbe9Sxc 	objp->so_len = sobjp->so_len;
8470ba2cbe9Sxc 	objp->so_class = sobjp->so_class;
8480ba2cbe9Sxc 	rw_exit(&drv_secobj_lock);
849*eae72b5bSSebastien Roy 	return (0);
8500ba2cbe9Sxc }
8510ba2cbe9Sxc 
8520ba2cbe9Sxc typedef struct dld_secobj_state {
8530ba2cbe9Sxc 	uint_t		ss_free;
8540ba2cbe9Sxc 	uint_t		ss_count;
8550ba2cbe9Sxc 	int		ss_rc;
856*eae72b5bSSebastien Roy 	int		ss_mode;
8570ba2cbe9Sxc 	dld_secobj_t	*ss_objp;
8580ba2cbe9Sxc } dld_secobj_state_t;
8590ba2cbe9Sxc 
8600ba2cbe9Sxc /* ARGSUSED */
8610ba2cbe9Sxc static uint_t
8620ba2cbe9Sxc drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
8630ba2cbe9Sxc {
8640ba2cbe9Sxc 	dld_secobj_state_t	*statep = arg;
8650ba2cbe9Sxc 	dld_secobj_t		*sobjp = (dld_secobj_t *)val;
8660ba2cbe9Sxc 
8670ba2cbe9Sxc 	if (statep->ss_free < sizeof (dld_secobj_t)) {
8680ba2cbe9Sxc 		statep->ss_rc = ENOSPC;
8690ba2cbe9Sxc 		return (MH_WALK_TERMINATE);
8700ba2cbe9Sxc 	}
871*eae72b5bSSebastien Roy 	if (ddi_copyout(sobjp, statep->ss_objp, sizeof (*sobjp),
872*eae72b5bSSebastien Roy 	    statep->ss_mode) != 0) {
873*eae72b5bSSebastien Roy 		statep->ss_rc = EFAULT;
874*eae72b5bSSebastien Roy 		return (MH_WALK_TERMINATE);
875*eae72b5bSSebastien Roy 	}
8760ba2cbe9Sxc 	statep->ss_objp++;
8770ba2cbe9Sxc 	statep->ss_free -= sizeof (dld_secobj_t);
8780ba2cbe9Sxc 	statep->ss_count++;
8790ba2cbe9Sxc 	return (MH_WALK_CONTINUE);
8800ba2cbe9Sxc }
8810ba2cbe9Sxc 
882*eae72b5bSSebastien Roy /* ARGSUSED */
883*eae72b5bSSebastien Roy static int
884*eae72b5bSSebastien Roy drv_ioc_secobj_get(void *karg, intptr_t arg, int mode, cred_t *cred)
8850ba2cbe9Sxc {
886*eae72b5bSSebastien Roy 	dld_ioc_secobj_get_t	*sgp = karg;
8870ba2cbe9Sxc 	dld_secobj_t		*sobjp, *objp;
888*eae72b5bSSebastien Roy 	int			err;
8890ba2cbe9Sxc 
8900ba2cbe9Sxc 	sobjp = &sgp->sg_obj;
8910ba2cbe9Sxc 
8920ba2cbe9Sxc 	if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0')
893*eae72b5bSSebastien Roy 		return (EINVAL);
8940ba2cbe9Sxc 
8950ba2cbe9Sxc 	rw_enter(&drv_secobj_lock, RW_READER);
8960ba2cbe9Sxc 	if (sobjp->so_name[0] != '\0') {
8970ba2cbe9Sxc 		err = mod_hash_find(drv_secobj_hash,
8980ba2cbe9Sxc 		    (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp);
8990ba2cbe9Sxc 		if (err != 0) {
9000ba2cbe9Sxc 			ASSERT(err == MH_ERR_NOTFOUND);
9010ba2cbe9Sxc 			rw_exit(&drv_secobj_lock);
902*eae72b5bSSebastien Roy 			return (ENOENT);
9030ba2cbe9Sxc 		}
9040ba2cbe9Sxc 		bcopy(objp->so_val, sobjp->so_val, objp->so_len);
9050ba2cbe9Sxc 		sobjp->so_len = objp->so_len;
9060ba2cbe9Sxc 		sobjp->so_class = objp->so_class;
9070ba2cbe9Sxc 		sgp->sg_count = 1;
9080ba2cbe9Sxc 	} else {
9090ba2cbe9Sxc 		dld_secobj_state_t	state;
9100ba2cbe9Sxc 
911*eae72b5bSSebastien Roy 		state.ss_free = sgp->sg_size - sizeof (dld_ioc_secobj_get_t);
9120ba2cbe9Sxc 		state.ss_count = 0;
9130ba2cbe9Sxc 		state.ss_rc = 0;
914*eae72b5bSSebastien Roy 		state.ss_mode = mode;
915*eae72b5bSSebastien Roy 		state.ss_objp = (dld_secobj_t *)((uchar_t *)arg +
916*eae72b5bSSebastien Roy 		    sizeof (dld_ioc_secobj_get_t));
917*eae72b5bSSebastien Roy 
9180ba2cbe9Sxc 		mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state);
9190ba2cbe9Sxc 		if (state.ss_rc != 0) {
9200ba2cbe9Sxc 			rw_exit(&drv_secobj_lock);
921*eae72b5bSSebastien Roy 			return (state.ss_rc);
9220ba2cbe9Sxc 		}
9230ba2cbe9Sxc 		sgp->sg_count = state.ss_count;
9240ba2cbe9Sxc 	}
9250ba2cbe9Sxc 	rw_exit(&drv_secobj_lock);
926*eae72b5bSSebastien Roy 	return (0);
9270ba2cbe9Sxc }
9280ba2cbe9Sxc 
929*eae72b5bSSebastien Roy /* ARGSUSED */
930*eae72b5bSSebastien Roy static int
931*eae72b5bSSebastien Roy drv_ioc_secobj_unset(void *karg, intptr_t arg, int mode, cred_t *cred)
9320ba2cbe9Sxc {
933*eae72b5bSSebastien Roy 	dld_ioc_secobj_unset_t	*sup = karg;
9340ba2cbe9Sxc 	dld_secobj_t		*objp;
9350ba2cbe9Sxc 	mod_hash_val_t		val;
936*eae72b5bSSebastien Roy 	int			err;
9370ba2cbe9Sxc 
9380ba2cbe9Sxc 	if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0')
939*eae72b5bSSebastien Roy 		return (EINVAL);
9400ba2cbe9Sxc 
9410ba2cbe9Sxc 	rw_enter(&drv_secobj_lock, RW_WRITER);
9420ba2cbe9Sxc 	err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name,
9430ba2cbe9Sxc 	    (mod_hash_val_t *)&objp);
9440ba2cbe9Sxc 	if (err != 0) {
9450ba2cbe9Sxc 		ASSERT(err == MH_ERR_NOTFOUND);
9460ba2cbe9Sxc 		rw_exit(&drv_secobj_lock);
947*eae72b5bSSebastien Roy 		return (ENOENT);
9480ba2cbe9Sxc 	}
949*eae72b5bSSebastien Roy 	VERIFY(mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name,
950*eae72b5bSSebastien Roy 	    (mod_hash_val_t *)&val) == 0);
9510ba2cbe9Sxc 	ASSERT(objp == (dld_secobj_t *)val);
9520ba2cbe9Sxc 
9530ba2cbe9Sxc 	kmem_cache_free(drv_secobj_cachep, objp);
9540ba2cbe9Sxc 	rw_exit(&drv_secobj_lock);
955*eae72b5bSSebastien Roy 	return (0);
956*eae72b5bSSebastien Roy }
957*eae72b5bSSebastien Roy 
958*eae72b5bSSebastien Roy static dld_ioc_info_t drv_ioc_list[] = {
959*eae72b5bSSebastien Roy 	{DLDIOC_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_attr_t),
960*eae72b5bSSebastien Roy 	    drv_ioc_attr},
961*eae72b5bSSebastien Roy 	{DLDIOC_PHYS_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_phys_attr_t),
962*eae72b5bSSebastien Roy 	    drv_ioc_phys_attr},
963*eae72b5bSSebastien Roy 	{DLDIOC_SECOBJ_SET, DLDCOPYIN | DLDDLCONFIG,
964*eae72b5bSSebastien Roy 	    sizeof (dld_ioc_secobj_set_t), drv_ioc_secobj_set},
965*eae72b5bSSebastien Roy 	{DLDIOC_SECOBJ_GET, DLDCOPYINOUT | DLDDLCONFIG,
966*eae72b5bSSebastien Roy 	    sizeof (dld_ioc_secobj_get_t), drv_ioc_secobj_get},
967*eae72b5bSSebastien Roy 	{DLDIOC_SECOBJ_UNSET, DLDCOPYIN | DLDDLCONFIG,
968*eae72b5bSSebastien Roy 	    sizeof (dld_ioc_secobj_unset_t), drv_ioc_secobj_unset},
969*eae72b5bSSebastien Roy 	{DLDIOC_CREATE_VLAN, DLDCOPYIN | DLDDLCONFIG,
970*eae72b5bSSebastien Roy 	    sizeof (dld_ioc_create_vlan_t), drv_ioc_create_vlan},
971*eae72b5bSSebastien Roy 	{DLDIOC_DELETE_VLAN, DLDCOPYIN | DLDDLCONFIG,
972*eae72b5bSSebastien Roy 	    sizeof (dld_ioc_delete_vlan_t),
973*eae72b5bSSebastien Roy 	    drv_ioc_delete_vlan},
974*eae72b5bSSebastien Roy 	{DLDIOC_VLAN_ATTR, DLDCOPYINOUT, sizeof (dld_ioc_vlan_attr_t),
975*eae72b5bSSebastien Roy 	    drv_ioc_vlan_attr},
976*eae72b5bSSebastien Roy 	{DLDIOC_DOORSERVER, DLDCOPYIN | DLDDLCONFIG, sizeof (dld_ioc_door_t),
977*eae72b5bSSebastien Roy 	    drv_ioc_doorserver},
978*eae72b5bSSebastien Roy 	{DLDIOC_RENAME, DLDCOPYIN | DLDDLCONFIG, sizeof (dld_ioc_rename_t),
979*eae72b5bSSebastien Roy 	    drv_ioc_rename},
980*eae72b5bSSebastien Roy 	{DLDIOC_GETMACPROP, DLDCOPYIN, sizeof (dld_ioc_macprop_t),
981*eae72b5bSSebastien Roy 	    drv_ioc_getprop},
982*eae72b5bSSebastien Roy 	{DLDIOC_SETMACPROP, DLDCOPYIN | DLDDLCONFIG, sizeof (dld_ioc_macprop_t),
983*eae72b5bSSebastien Roy 	    drv_ioc_setprop}
984*eae72b5bSSebastien Roy };
985*eae72b5bSSebastien Roy 
986*eae72b5bSSebastien Roy typedef struct dld_ioc_modentry {
987*eae72b5bSSebastien Roy 	uint16_t	dim_modid;	/* Top 16 bits of ioctl command */
988*eae72b5bSSebastien Roy 	char		*dim_modname;	/* Module to be loaded */
989*eae72b5bSSebastien Roy 	dld_ioc_info_t	*dim_list;	/* array of ioctl structures */
990*eae72b5bSSebastien Roy 	uint_t		dim_count;	/* number of elements in dim_list */
991*eae72b5bSSebastien Roy } dld_ioc_modentry_t;
992*eae72b5bSSebastien Roy 
993*eae72b5bSSebastien Roy /*
994*eae72b5bSSebastien Roy  * For all modules except for dld, dim_list and dim_count are assigned
995*eae72b5bSSebastien Roy  * when the modules register their ioctls in dld_ioc_register().  We
996*eae72b5bSSebastien Roy  * can statically initialize dld's ioctls in-line here; there's no
997*eae72b5bSSebastien Roy  * need for it to call dld_ioc_register() itself.
998*eae72b5bSSebastien Roy  */
999*eae72b5bSSebastien Roy static dld_ioc_modentry_t dld_ioc_modtable[] = {
1000*eae72b5bSSebastien Roy 	{DLD_IOC,	"dld",	drv_ioc_list, DLDIOCCNT(drv_ioc_list)},
1001*eae72b5bSSebastien Roy 	{AGGR_IOC,	"aggr",	NULL, 0},
1002*eae72b5bSSebastien Roy 	{VNIC_IOC,	"vnic",	NULL, 0}
1003*eae72b5bSSebastien Roy };
1004*eae72b5bSSebastien Roy #define	DLDIOC_CNT	\
1005*eae72b5bSSebastien Roy 	(sizeof (dld_ioc_modtable) / sizeof (dld_ioc_modentry_t))
1006*eae72b5bSSebastien Roy 
1007*eae72b5bSSebastien Roy static dld_ioc_modentry_t *
1008*eae72b5bSSebastien Roy dld_ioc_findmod(uint16_t modid)
1009*eae72b5bSSebastien Roy {
1010*eae72b5bSSebastien Roy 	int	i;
1011*eae72b5bSSebastien Roy 
1012*eae72b5bSSebastien Roy 	for (i = 0; i < DLDIOC_CNT; i++) {
1013*eae72b5bSSebastien Roy 		if (modid == dld_ioc_modtable[i].dim_modid)
1014*eae72b5bSSebastien Roy 			return (&dld_ioc_modtable[i]);
1015*eae72b5bSSebastien Roy 	}
1016*eae72b5bSSebastien Roy 	return (NULL);
1017*eae72b5bSSebastien Roy }
1018*eae72b5bSSebastien Roy 
1019*eae72b5bSSebastien Roy int
1020*eae72b5bSSebastien Roy dld_ioc_register(uint16_t modid, dld_ioc_info_t *list, uint_t count)
1021*eae72b5bSSebastien Roy {
1022*eae72b5bSSebastien Roy 	dld_ioc_modentry_t *dim = dld_ioc_findmod(modid);
1023*eae72b5bSSebastien Roy 
1024*eae72b5bSSebastien Roy 	if (dim == NULL)
1025*eae72b5bSSebastien Roy 		return (ENOENT);
1026*eae72b5bSSebastien Roy 
1027*eae72b5bSSebastien Roy 	dim->dim_list = list;
1028*eae72b5bSSebastien Roy 	dim->dim_count = count;
1029*eae72b5bSSebastien Roy 	return (0);
1030*eae72b5bSSebastien Roy }
1031*eae72b5bSSebastien Roy 
1032*eae72b5bSSebastien Roy void
1033*eae72b5bSSebastien Roy dld_ioc_unregister(uint16_t modid)
1034*eae72b5bSSebastien Roy {
1035*eae72b5bSSebastien Roy 	VERIFY(dld_ioc_register(modid, NULL, 0) == 0);
1036*eae72b5bSSebastien Roy }
10370ba2cbe9Sxc 
1038*eae72b5bSSebastien Roy /*
1039*eae72b5bSSebastien Roy  * The general design with GLDv3 ioctls is that all ioctls issued
1040*eae72b5bSSebastien Roy  * through /dev/dld go through this drv_ioctl() function.  This
1041*eae72b5bSSebastien Roy  * function handles all ioctls on behalf of modules listed in
1042*eae72b5bSSebastien Roy  * dld_ioc_modtable.
1043*eae72b5bSSebastien Roy  *
1044*eae72b5bSSebastien Roy  * When an ioctl is received, this function looks for the associated
1045*eae72b5bSSebastien Roy  * module-id-specific ioctl information using dld_ioc_findmod().  The
1046*eae72b5bSSebastien Roy  * call to ddi_hold_devi_by_instance() on the associated device will
1047*eae72b5bSSebastien Roy  * cause the kernel module responsible for the ioctl to be loaded if
1048*eae72b5bSSebastien Roy  * it's not already loaded, which should result in that module calling
1049*eae72b5bSSebastien Roy  * dld_ioc_register(), thereby filling in the dim_list containing the
1050*eae72b5bSSebastien Roy  * details for the ioctl being processed.
1051*eae72b5bSSebastien Roy  *
1052*eae72b5bSSebastien Roy  * This function can then perform operations such as copyin() data and
1053*eae72b5bSSebastien Roy  * do credential checks based on the registered ioctl information,
1054*eae72b5bSSebastien Roy  * then issue the callback function di_func() registered by the
1055*eae72b5bSSebastien Roy  * responsible module.  Upon return, the appropriate copyout()
1056*eae72b5bSSebastien Roy  * operation can be performed and the operation completes.
1057*eae72b5bSSebastien Roy  */
1058*eae72b5bSSebastien Roy /* ARGSUSED */
1059*eae72b5bSSebastien Roy static int
1060*eae72b5bSSebastien Roy drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred, int *rvalp)
1061*eae72b5bSSebastien Roy {
1062*eae72b5bSSebastien Roy 	dld_ioc_modentry_t *dim;
1063*eae72b5bSSebastien Roy 	dld_ioc_info_t	*info;
1064*eae72b5bSSebastien Roy 	dev_info_t	*dip = NULL;
1065*eae72b5bSSebastien Roy 	void		*buf = NULL;
1066*eae72b5bSSebastien Roy 	size_t		sz;
1067*eae72b5bSSebastien Roy 	int		i, err;
1068*eae72b5bSSebastien Roy 
1069*eae72b5bSSebastien Roy 	if ((dim = dld_ioc_findmod(DLD_IOC_MODID(cmd))) == NULL)
1070*eae72b5bSSebastien Roy 		return (ENOTSUP);
1071*eae72b5bSSebastien Roy 
1072*eae72b5bSSebastien Roy 	dip = ddi_hold_devi_by_instance(ddi_name_to_major(dim->dim_modname),
1073*eae72b5bSSebastien Roy 	    0, 0);
1074*eae72b5bSSebastien Roy 	if (dip == NULL || dim->dim_list == NULL) {
1075*eae72b5bSSebastien Roy 		err = ENODEV;
1076*eae72b5bSSebastien Roy 		goto done;
1077*eae72b5bSSebastien Roy 	}
1078*eae72b5bSSebastien Roy 
1079*eae72b5bSSebastien Roy 	for (i = 0; i < dim->dim_count; i++) {
1080*eae72b5bSSebastien Roy 		if (cmd == dim->dim_list[i].di_cmd)
1081*eae72b5bSSebastien Roy 			break;
1082*eae72b5bSSebastien Roy 	}
1083*eae72b5bSSebastien Roy 	if (i == dim->dim_count) {
1084*eae72b5bSSebastien Roy 		err = ENOTSUP;
1085*eae72b5bSSebastien Roy 		goto done;
1086*eae72b5bSSebastien Roy 	}
1087*eae72b5bSSebastien Roy 
1088*eae72b5bSSebastien Roy 	info = &dim->dim_list[i];
1089*eae72b5bSSebastien Roy 
1090*eae72b5bSSebastien Roy 	if ((info->di_flags & DLDDLCONFIG) && secpolicy_dl_config(cred) != 0) {
1091*eae72b5bSSebastien Roy 		err = EPERM;
1092*eae72b5bSSebastien Roy 		goto done;
1093*eae72b5bSSebastien Roy 	}
1094*eae72b5bSSebastien Roy 
1095*eae72b5bSSebastien Roy 	sz = info->di_argsize;
1096*eae72b5bSSebastien Roy 	if ((buf = kmem_zalloc(sz, KM_NOSLEEP)) == NULL) {
1097*eae72b5bSSebastien Roy 		err = ENOMEM;
1098*eae72b5bSSebastien Roy 		goto done;
1099*eae72b5bSSebastien Roy 	}
1100*eae72b5bSSebastien Roy 
1101*eae72b5bSSebastien Roy 	if ((info->di_flags & DLDCOPYIN) &&
1102*eae72b5bSSebastien Roy 	    ddi_copyin((void *)arg, buf, sz, mode) != 0) {
1103*eae72b5bSSebastien Roy 		err = EFAULT;
1104*eae72b5bSSebastien Roy 		goto done;
1105*eae72b5bSSebastien Roy 	}
1106*eae72b5bSSebastien Roy 
1107*eae72b5bSSebastien Roy 	err = info->di_func(buf, arg, mode, cred);
1108*eae72b5bSSebastien Roy 
1109*eae72b5bSSebastien Roy 	if ((info->di_flags & DLDCOPYOUT) &&
1110*eae72b5bSSebastien Roy 	    ddi_copyout(buf, (void *)arg, sz, mode) != 0 && err == 0)
1111*eae72b5bSSebastien Roy 		err = EFAULT;
1112*eae72b5bSSebastien Roy 
1113*eae72b5bSSebastien Roy done:
1114*eae72b5bSSebastien Roy 	if (buf != NULL)
1115*eae72b5bSSebastien Roy 		kmem_free(buf, sz);
1116*eae72b5bSSebastien Roy 	if (dip != NULL)
1117*eae72b5bSSebastien Roy 		ddi_release_devi(dip);
1118*eae72b5bSSebastien Roy 	return (err);
11190ba2cbe9Sxc }
1120