xref: /illumos-gate/usr/src/uts/common/io/dld/dld_drv.c (revision d62bc4ba)
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 /*
22*d62bc4baSyz  * 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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Data-Link Driver
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include	<sys/conf.h>
33210db224Sericheng #include	<sys/mkdev.h>
347c478bd9Sstevel@tonic-gate #include	<sys/modctl.h>
35210db224Sericheng #include	<sys/stat.h>
36210db224Sericheng #include	<sys/strsun.h>
37*d62bc4baSyz #include	<sys/vlan.h>
387c478bd9Sstevel@tonic-gate #include	<sys/dld.h>
397c478bd9Sstevel@tonic-gate #include	<sys/dld_impl.h>
40210db224Sericheng #include	<sys/dls_impl.h>
41*d62bc4baSyz #include	<sys/softmac.h>
42f4b3ec61Sdh #include 	<sys/vlan.h>
43210db224Sericheng #include	<inet/common.h>
44210db224Sericheng 
45210db224Sericheng /*
46210db224Sericheng  * dld control node state, one per open control node session.
47210db224Sericheng  */
48210db224Sericheng typedef struct dld_ctl_str_s {
49210db224Sericheng 	minor_t cs_minor;
50210db224Sericheng 	queue_t *cs_wq;
51210db224Sericheng } dld_ctl_str_t;
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static void	drv_init(void);
547c478bd9Sstevel@tonic-gate static int	drv_fini(void);
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static int	drv_getinfo(dev_info_t	*, ddi_info_cmd_t, void *, void **);
577c478bd9Sstevel@tonic-gate static int	drv_attach(dev_info_t *, ddi_attach_cmd_t);
587c478bd9Sstevel@tonic-gate static int	drv_detach(dev_info_t *, ddi_detach_cmd_t);
597c478bd9Sstevel@tonic-gate 
600ba2cbe9Sxc /*
610ba2cbe9Sxc  * Secure objects declarations
620ba2cbe9Sxc  */
630ba2cbe9Sxc #define	SECOBJ_WEP_HASHSZ	67
640ba2cbe9Sxc static krwlock_t	drv_secobj_lock;
650ba2cbe9Sxc static kmem_cache_t	*drv_secobj_cachep;
660ba2cbe9Sxc static mod_hash_t	*drv_secobj_hash;
670ba2cbe9Sxc static void		drv_secobj_init(void);
680ba2cbe9Sxc static void		drv_secobj_fini(void);
690ba2cbe9Sxc static void		drv_ioc_secobj_set(dld_ctl_str_t *, mblk_t *);
700ba2cbe9Sxc static void		drv_ioc_secobj_get(dld_ctl_str_t *, mblk_t *);
710ba2cbe9Sxc static void		drv_ioc_secobj_unset(dld_ctl_str_t *, mblk_t *);
720ba2cbe9Sxc 
73210db224Sericheng /*
74210db224Sericheng  * The following entry points are private to dld and are used for control
75210db224Sericheng  * operations only. The entry points exported to mac drivers are defined
76210db224Sericheng  * in dld_str.c. Refer to the comment on top of dld_str.c for details.
77210db224Sericheng  */
787c478bd9Sstevel@tonic-gate static int	drv_open(queue_t *, dev_t *, int, int, cred_t *);
797c478bd9Sstevel@tonic-gate static int	drv_close(queue_t *);
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static void	drv_uw_put(queue_t *, mblk_t *);
827c478bd9Sstevel@tonic-gate static void	drv_uw_srv(queue_t *);
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate dev_info_t	*dld_dip;		/* dev_info_t for the driver */
85210db224Sericheng uint32_t	dld_opt = 0;		/* Global options */
86210db224Sericheng static vmem_t	*dld_ctl_vmem;		/* for control minor numbers */
877c478bd9Sstevel@tonic-gate 
88*d62bc4baSyz #define	NAUTOPUSH 32
89*d62bc4baSyz static mod_hash_t *dld_ap_hashp;
90*d62bc4baSyz static krwlock_t dld_ap_hash_lock;
91*d62bc4baSyz 
927c478bd9Sstevel@tonic-gate static	struct	module_info	drv_info = {
937c478bd9Sstevel@tonic-gate 	0,			/* mi_idnum */
947c478bd9Sstevel@tonic-gate 	DLD_DRIVER_NAME,	/* mi_idname */
957c478bd9Sstevel@tonic-gate 	0,			/* mi_minpsz */
967c478bd9Sstevel@tonic-gate 	(64 * 1024),		/* mi_maxpsz */
977c478bd9Sstevel@tonic-gate 	1,			/* mi_hiwat */
987c478bd9Sstevel@tonic-gate 	0			/* mi_lowat */
997c478bd9Sstevel@tonic-gate };
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static	struct qinit		drv_ur_init = {
1027c478bd9Sstevel@tonic-gate 	NULL,			/* qi_putp */
1037c478bd9Sstevel@tonic-gate 	NULL,			/* qi_srvp */
1047c478bd9Sstevel@tonic-gate 	drv_open,		/* qi_qopen */
1057c478bd9Sstevel@tonic-gate 	drv_close,		/* qi_qclose */
1067c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
1077c478bd9Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
1087c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
1097c478bd9Sstevel@tonic-gate };
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static	struct qinit		drv_uw_init = {
1127c478bd9Sstevel@tonic-gate 	(pfi_t)drv_uw_put,	/* qi_putp */
1137c478bd9Sstevel@tonic-gate 	(pfi_t)drv_uw_srv,	/* qi_srvp */
1147c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qopen */
1157c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qclose */
1167c478bd9Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
1177c478bd9Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
1187c478bd9Sstevel@tonic-gate 	NULL			/* qi_mstat */
1197c478bd9Sstevel@tonic-gate };
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate static	struct streamtab	drv_stream = {
1227c478bd9Sstevel@tonic-gate 	&drv_ur_init,		/* st_rdinit */
1237c478bd9Sstevel@tonic-gate 	&drv_uw_init,		/* st_wrinit */
1247c478bd9Sstevel@tonic-gate 	NULL,			/* st_muxrinit */
1257c478bd9Sstevel@tonic-gate 	NULL			/* st_muxwinit */
1267c478bd9Sstevel@tonic-gate };
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach,
129210db224Sericheng     nodev, drv_getinfo, D_MP, &drv_stream);
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
1337c478bd9Sstevel@tonic-gate  */
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate extern	struct mod_ops		mod_driverops;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static	struct modldrv		drv_modldrv = {
1387c478bd9Sstevel@tonic-gate 	&mod_driverops,
1397c478bd9Sstevel@tonic-gate 	DLD_INFO,
1407c478bd9Sstevel@tonic-gate 	&drv_ops
1417c478bd9Sstevel@tonic-gate };
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate static	struct modlinkage	drv_modlinkage = {
1447c478bd9Sstevel@tonic-gate 	MODREV_1,
1457c478bd9Sstevel@tonic-gate 	&drv_modldrv,
1467c478bd9Sstevel@tonic-gate 	NULL
1477c478bd9Sstevel@tonic-gate };
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate int
1507c478bd9Sstevel@tonic-gate _init(void)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	int	err;
1537c478bd9Sstevel@tonic-gate 
154210db224Sericheng 	drv_init();
155210db224Sericheng 
1567c478bd9Sstevel@tonic-gate 	if ((err = mod_install(&drv_modlinkage)) != 0)
1577c478bd9Sstevel@tonic-gate 		return (err);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	return (0);
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate int
1637c478bd9Sstevel@tonic-gate _fini(void)
1647c478bd9Sstevel@tonic-gate {
1657c478bd9Sstevel@tonic-gate 	int	err;
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	if ((err = mod_remove(&drv_modlinkage)) != 0)
1687c478bd9Sstevel@tonic-gate 		return (err);
1697c478bd9Sstevel@tonic-gate 
170210db224Sericheng 	if (drv_fini() != 0) {
171210db224Sericheng 		(void) mod_install(&drv_modlinkage);
172210db224Sericheng 		return (DDI_FAILURE);
173210db224Sericheng 	}
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 	return (err);
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate int
1797c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
1807c478bd9Sstevel@tonic-gate {
1817c478bd9Sstevel@tonic-gate 	return (mod_info(&drv_modlinkage, modinfop));
1827c478bd9Sstevel@tonic-gate }
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /*
185210db224Sericheng  * Initialize component modules.
1867c478bd9Sstevel@tonic-gate  */
1877c478bd9Sstevel@tonic-gate static void
1887c478bd9Sstevel@tonic-gate drv_init(void)
1897c478bd9Sstevel@tonic-gate {
190210db224Sericheng 	dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1,
191210db224Sericheng 	    NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER);
1920ba2cbe9Sxc 	drv_secobj_init();
1937c478bd9Sstevel@tonic-gate 	dld_str_init();
194*d62bc4baSyz 	/*
195*d62bc4baSyz 	 * Create a hash table for autopush configuration.
196*d62bc4baSyz 	 */
197*d62bc4baSyz 	dld_ap_hashp = mod_hash_create_idhash("dld_autopush_hash",
198*d62bc4baSyz 	    NAUTOPUSH, mod_hash_null_valdtor);
199*d62bc4baSyz 
200*d62bc4baSyz 	ASSERT(dld_ap_hashp != NULL);
201*d62bc4baSyz 	rw_init(&dld_ap_hash_lock, NULL, RW_DRIVER, NULL);
202*d62bc4baSyz }
203*d62bc4baSyz 
204*d62bc4baSyz /* ARGSUSED */
205*d62bc4baSyz static uint_t
206*d62bc4baSyz drv_ap_exist(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
207*d62bc4baSyz {
208*d62bc4baSyz 	boolean_t *pexist = arg;
209*d62bc4baSyz 
210*d62bc4baSyz 	*pexist = B_TRUE;
211*d62bc4baSyz 	return (MH_WALK_TERMINATE);
2127c478bd9Sstevel@tonic-gate }
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate static int
2157c478bd9Sstevel@tonic-gate drv_fini(void)
2167c478bd9Sstevel@tonic-gate {
217*d62bc4baSyz 	int		err;
218*d62bc4baSyz 	boolean_t	exist = B_FALSE;
219*d62bc4baSyz 
220*d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_READER);
221*d62bc4baSyz 	mod_hash_walk(dld_ap_hashp, drv_ap_exist, &exist);
222*d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
223*d62bc4baSyz 
224*d62bc4baSyz 	if (exist)
225*d62bc4baSyz 		return (EBUSY);
2267c478bd9Sstevel@tonic-gate 
227210db224Sericheng 	if ((err = dld_str_fini()) != 0)
2287c478bd9Sstevel@tonic-gate 		return (err);
2297c478bd9Sstevel@tonic-gate 
2300ba2cbe9Sxc 	drv_secobj_fini();
231210db224Sericheng 	vmem_destroy(dld_ctl_vmem);
232*d62bc4baSyz 	mod_hash_destroy_idhash(dld_ap_hashp);
233*d62bc4baSyz 	rw_destroy(&dld_ap_hash_lock);
2347c478bd9Sstevel@tonic-gate 	return (0);
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * devo_getinfo: getinfo(9e)
2397c478bd9Sstevel@tonic-gate  */
2407c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2417c478bd9Sstevel@tonic-gate static int
2427c478bd9Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate 	if (dld_dip == NULL)
2457c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate 	switch (cmd) {
2487c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2497c478bd9Sstevel@tonic-gate 		*resp = (void *)0;
2507c478bd9Sstevel@tonic-gate 		break;
2517c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2527c478bd9Sstevel@tonic-gate 		*resp = (void *)dld_dip;
2537c478bd9Sstevel@tonic-gate 		break;
2547c478bd9Sstevel@tonic-gate 	default:
2557c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate /*
2627c478bd9Sstevel@tonic-gate  * Check properties to set options. (See dld.h for property definitions).
2637c478bd9Sstevel@tonic-gate  */
2647c478bd9Sstevel@tonic-gate static void
2657c478bd9Sstevel@tonic-gate drv_set_opt(dev_info_t *dip)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2687c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_FASTPATH, 0) != 0) {
2697c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_FASTPATH;
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2737c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_POLL, 0) != 0) {
2747c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_POLL;
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2787c478bd9Sstevel@tonic-gate 	    DLD_PROP_NO_ZEROCOPY, 0) != 0) {
2797c478bd9Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_ZEROCOPY;
2807c478bd9Sstevel@tonic-gate 	}
2819c175129Sja 
2829c175129Sja 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2839c175129Sja 	    DLD_PROP_NO_SOFTRING, 0) != 0) {
2849c175129Sja 		dld_opt |= DLD_OPT_NO_SOFTRING;
2859c175129Sja 	}
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate /*
2897c478bd9Sstevel@tonic-gate  * devo_attach: attach(9e)
2907c478bd9Sstevel@tonic-gate  */
2917c478bd9Sstevel@tonic-gate static int
2927c478bd9Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate 	if (cmd != DDI_ATTACH)
2957c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	ASSERT(ddi_get_instance(dip) == 0);
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate 	drv_set_opt(dip);
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	/*
3027c478bd9Sstevel@tonic-gate 	 * Create control node. DLPI provider nodes will be created on demand.
3037c478bd9Sstevel@tonic-gate 	 */
3047c478bd9Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR,
3057c478bd9Sstevel@tonic-gate 	    DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS)
3067c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	dld_dip = dip;
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/*
3117c478bd9Sstevel@tonic-gate 	 * Log the fact that the driver is now attached.
3127c478bd9Sstevel@tonic-gate 	 */
3137c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
3147c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate  * devo_detach: detach(9e)
3197c478bd9Sstevel@tonic-gate  */
3207c478bd9Sstevel@tonic-gate static int
3217c478bd9Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
3247c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	ASSERT(dld_dip == dip);
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	/*
3297c478bd9Sstevel@tonic-gate 	 * Remove the control node.
3307c478bd9Sstevel@tonic-gate 	 */
3317c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME);
3327c478bd9Sstevel@tonic-gate 	dld_dip = NULL;
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3357c478bd9Sstevel@tonic-gate }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate /*
338210db224Sericheng  * dld control node open procedure.
3397c478bd9Sstevel@tonic-gate  */
3407c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3417c478bd9Sstevel@tonic-gate static int
3427c478bd9Sstevel@tonic-gate drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
3437c478bd9Sstevel@tonic-gate {
344210db224Sericheng 	dld_ctl_str_t	*ctls;
3457c478bd9Sstevel@tonic-gate 	minor_t		minor;
346210db224Sericheng 	queue_t *oq =	OTHERQ(rq);
3477c478bd9Sstevel@tonic-gate 
348210db224Sericheng 	if (sflag == MODOPEN)
349210db224Sericheng 		return (ENOTSUP);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	/*
3527c478bd9Sstevel@tonic-gate 	 * This is a cloning driver and therefore each queue should only
3537c478bd9Sstevel@tonic-gate 	 * ever get opened once.
3547c478bd9Sstevel@tonic-gate 	 */
3557c478bd9Sstevel@tonic-gate 	if (rq->q_ptr != NULL)
3567c478bd9Sstevel@tonic-gate 		return (EBUSY);
3577c478bd9Sstevel@tonic-gate 
358210db224Sericheng 	minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP);
359210db224Sericheng 	if (minor == 0)
360210db224Sericheng 		return (ENOMEM);
3617c478bd9Sstevel@tonic-gate 
362210db224Sericheng 	ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP);
363210db224Sericheng 	if (ctls == NULL) {
364210db224Sericheng 		vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1);
365210db224Sericheng 		return (ENOMEM);
366210db224Sericheng 	}
3677c478bd9Sstevel@tonic-gate 
368210db224Sericheng 	ctls->cs_minor = minor;
369210db224Sericheng 	ctls->cs_wq = WR(rq);
3707c478bd9Sstevel@tonic-gate 
371210db224Sericheng 	rq->q_ptr = ctls;
372210db224Sericheng 	oq->q_ptr = ctls;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	/*
3757c478bd9Sstevel@tonic-gate 	 * Enable the queue srv(9e) routine.
3767c478bd9Sstevel@tonic-gate 	 */
3777c478bd9Sstevel@tonic-gate 	qprocson(rq);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	/*
3807c478bd9Sstevel@tonic-gate 	 * Construct a cloned dev_t to hand back.
3817c478bd9Sstevel@tonic-gate 	 */
382210db224Sericheng 	*devp = makedevice(getmajor(*devp), ctls->cs_minor);
3837c478bd9Sstevel@tonic-gate 	return (0);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate /*
387210db224Sericheng  * dld control node close procedure.
3887c478bd9Sstevel@tonic-gate  */
3897c478bd9Sstevel@tonic-gate static int
3907c478bd9Sstevel@tonic-gate drv_close(queue_t *rq)
3917c478bd9Sstevel@tonic-gate {
392210db224Sericheng 	dld_ctl_str_t	*ctls;
3937c478bd9Sstevel@tonic-gate 
394210db224Sericheng 	ctls = rq->q_ptr;
395210db224Sericheng 	ASSERT(ctls != NULL);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	/*
3987c478bd9Sstevel@tonic-gate 	 * Disable the queue srv(9e) routine.
3997c478bd9Sstevel@tonic-gate 	 */
4007c478bd9Sstevel@tonic-gate 	qprocsoff(rq);
4017c478bd9Sstevel@tonic-gate 
402210db224Sericheng 	vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1);
403210db224Sericheng 
404210db224Sericheng 	kmem_free(ctls, sizeof (dld_ctl_str_t));
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	return (0);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /*
410*d62bc4baSyz  * DLDIOC_ATTR
4117c478bd9Sstevel@tonic-gate  */
4127c478bd9Sstevel@tonic-gate static void
413210db224Sericheng drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp)
4147c478bd9Sstevel@tonic-gate {
415*d62bc4baSyz 	dld_ioc_attr_t		*diap;
416*d62bc4baSyz 	dls_dl_handle_t		dlh;
417*d62bc4baSyz 	dls_vlan_t		*dvp;
418*d62bc4baSyz 	int			err;
419*d62bc4baSyz 	queue_t			*q = ctls->cs_wq;
4207c478bd9Sstevel@tonic-gate 
421210db224Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0)
422210db224Sericheng 		goto failed;
4237c478bd9Sstevel@tonic-gate 
424210db224Sericheng 	diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr;
425210db224Sericheng 
426*d62bc4baSyz 	if ((err = dls_devnet_hold_tmp(diap->dia_linkid, &dlh)) != 0)
427210db224Sericheng 		goto failed;
428210db224Sericheng 
429*d62bc4baSyz 	if ((err = dls_vlan_hold(dls_devnet_mac(dlh),
430*d62bc4baSyz 	    dls_devnet_vid(dlh), &dvp, B_FALSE, B_FALSE)) != 0) {
431*d62bc4baSyz 		dls_devnet_rele_tmp(dlh);
432*d62bc4baSyz 		goto failed;
433*d62bc4baSyz 	}
434210db224Sericheng 
435*d62bc4baSyz 	diap->dia_max_sdu = dvp->dv_dlp->dl_mip->mi_sdu_max;
436210db224Sericheng 	dls_vlan_rele(dvp);
437*d62bc4baSyz 	dls_devnet_rele_tmp(dlh);
438*d62bc4baSyz 
439210db224Sericheng 	miocack(q, mp, sizeof (dld_ioc_attr_t), 0);
440210db224Sericheng 	return;
441210db224Sericheng 
442210db224Sericheng failed:
443210db224Sericheng 	ASSERT(err != 0);
444*d62bc4baSyz 	miocnak(q, mp, 0, err);
445*d62bc4baSyz }
446210db224Sericheng 
447*d62bc4baSyz /*
448*d62bc4baSyz  * DLDIOC_PHYS_ATTR
449*d62bc4baSyz  */
450*d62bc4baSyz static void
451*d62bc4baSyz drv_ioc_phys_attr(dld_ctl_str_t *ctls, mblk_t *mp)
452*d62bc4baSyz {
453*d62bc4baSyz 	dld_ioc_phys_attr_t	*dipp;
454*d62bc4baSyz 	int			err;
455*d62bc4baSyz 	dls_dl_handle_t		dlh;
456*d62bc4baSyz 	dls_dev_handle_t	ddh;
457*d62bc4baSyz 	dev_t			phydev;
458*d62bc4baSyz 	queue_t			*q = ctls->cs_wq;
459*d62bc4baSyz 
460*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_phys_attr_t))) != 0)
461*d62bc4baSyz 		goto failed;
462*d62bc4baSyz 
463*d62bc4baSyz 	dipp = (dld_ioc_phys_attr_t *)mp->b_cont->b_rptr;
464*d62bc4baSyz 
465*d62bc4baSyz 	/*
466*d62bc4baSyz 	 * Every physical link should have its physical dev_t kept in the
467*d62bc4baSyz 	 * daemon. If not, it is not a valid physical link.
468*d62bc4baSyz 	 */
469*d62bc4baSyz 	if (dls_mgmt_get_phydev(dipp->dip_linkid, &phydev) != 0) {
470*d62bc4baSyz 		err = EINVAL;
471*d62bc4baSyz 		goto failed;
472*d62bc4baSyz 	}
473*d62bc4baSyz 
474*d62bc4baSyz 	/*
475*d62bc4baSyz 	 * Although this is a valid physical link, it might already be removed
476*d62bc4baSyz 	 * by DR or during system shutdown. softmac_hold_device() would return
477*d62bc4baSyz 	 * ENOENT in this case.
478*d62bc4baSyz 	 */
479*d62bc4baSyz 	if ((err = softmac_hold_device(phydev, &ddh)) != 0)
480*d62bc4baSyz 		goto failed;
481*d62bc4baSyz 
482*d62bc4baSyz 	if (dls_devnet_hold_tmp(dipp->dip_linkid, &dlh) != 0) {
483210db224Sericheng 		/*
484*d62bc4baSyz 		 * Although this is an active physical link, its link type is
485*d62bc4baSyz 		 * not supported by GLDv3, and therefore it does not have
486*d62bc4baSyz 		 * vanity naming support.
487210db224Sericheng 		 */
488*d62bc4baSyz 		dipp->dip_novanity = B_TRUE;
489*d62bc4baSyz 	} else {
490*d62bc4baSyz 		dipp->dip_novanity = B_FALSE;
491*d62bc4baSyz 		dls_devnet_rele_tmp(dlh);
492210db224Sericheng 	}
493*d62bc4baSyz 	/*
494*d62bc4baSyz 	 * Get the physical device name from the major number and the instance
495*d62bc4baSyz 	 * number derived from phydev.
496*d62bc4baSyz 	 */
497*d62bc4baSyz 	(void) snprintf(dipp->dip_dev, MAXLINKNAMELEN, "%s%d",
498*d62bc4baSyz 	    ddi_major_to_name(getmajor(phydev)), getminor(phydev) - 1);
499*d62bc4baSyz 
500*d62bc4baSyz 	softmac_rele_device(ddh);
501*d62bc4baSyz 
502*d62bc4baSyz 	miocack(q, mp, sizeof (dld_ioc_phys_attr_t), 0);
503*d62bc4baSyz 	return;
504*d62bc4baSyz 
505*d62bc4baSyz failed:
506210db224Sericheng 	miocnak(q, mp, 0, err);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate /*
510*d62bc4baSyz  * DLDIOC_CREATE_VLAN
5117c478bd9Sstevel@tonic-gate  */
512*d62bc4baSyz static void
513*d62bc4baSyz drv_ioc_create_vlan(dld_ctl_str_t *ctls, mblk_t *mp)
514210db224Sericheng {
515*d62bc4baSyz 	dld_ioc_create_vlan_t	*dicp;
516*d62bc4baSyz 	int			err;
517*d62bc4baSyz 	queue_t			*q = ctls->cs_wq;
518210db224Sericheng 
519*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_create_vlan_t))) != 0)
520*d62bc4baSyz 		goto failed;
521*d62bc4baSyz 
522*d62bc4baSyz 	dicp = (dld_ioc_create_vlan_t *)mp->b_cont->b_rptr;
523*d62bc4baSyz 
524*d62bc4baSyz 	if ((err = dls_devnet_create_vlan(dicp->dic_vlanid,
525*d62bc4baSyz 	    dicp->dic_linkid, dicp->dic_vid, dicp->dic_force)) != 0) {
526*d62bc4baSyz 		goto failed;
527aae21359Skrgopi 	}
528*d62bc4baSyz 
529*d62bc4baSyz 	miocack(q, mp, 0, 0);
530*d62bc4baSyz 	return;
531*d62bc4baSyz 
532*d62bc4baSyz failed:
533*d62bc4baSyz 	miocnak(q, mp, 0, err);
534210db224Sericheng }
535210db224Sericheng 
536*d62bc4baSyz /*
537*d62bc4baSyz  * DLDIOC_DELETE_VLAN
538*d62bc4baSyz  */
5397c478bd9Sstevel@tonic-gate static void
540*d62bc4baSyz drv_ioc_delete_vlan(dld_ctl_str_t *ctls, mblk_t *mp)
5417c478bd9Sstevel@tonic-gate {
542*d62bc4baSyz 	dld_ioc_delete_vlan_t	*didp;
543*d62bc4baSyz 	int			err;
544210db224Sericheng 	queue_t			*q = ctls->cs_wq;
5457c478bd9Sstevel@tonic-gate 
546*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_delete_vlan_t))) != 0)
547*d62bc4baSyz 		goto done;
5487c478bd9Sstevel@tonic-gate 
549*d62bc4baSyz 	didp = (dld_ioc_delete_vlan_t *)mp->b_cont->b_rptr;
550*d62bc4baSyz 	err = dls_devnet_destroy_vlan(didp->did_linkid);
551*d62bc4baSyz 
552*d62bc4baSyz done:
553*d62bc4baSyz 	if (err == 0)
554*d62bc4baSyz 		miocack(q, mp, 0, 0);
555*d62bc4baSyz 	else
556*d62bc4baSyz 		miocnak(q, mp, 0, err);
557*d62bc4baSyz }
558*d62bc4baSyz 
559*d62bc4baSyz /*
560*d62bc4baSyz  * DLDIOC_VLAN_ATTR
561*d62bc4baSyz  */
562*d62bc4baSyz static void
563*d62bc4baSyz drv_ioc_vlan_attr(dld_ctl_str_t *ctls, mblk_t *mp)
564*d62bc4baSyz {
565*d62bc4baSyz 	dld_ioc_vlan_attr_t	*divp;
566*d62bc4baSyz 	dls_dl_handle_t		dlh;
567*d62bc4baSyz 	uint16_t		vid;
568*d62bc4baSyz 	dls_vlan_t		*dvp;
569*d62bc4baSyz 	int			err;
570*d62bc4baSyz 	queue_t			*q = ctls->cs_wq;
571*d62bc4baSyz 
572*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_attr_t))) != 0)
573aae21359Skrgopi 		goto failed;
574aae21359Skrgopi 
575*d62bc4baSyz 	divp = (dld_ioc_vlan_attr_t *)mp->b_cont->b_rptr;
5767c478bd9Sstevel@tonic-gate 
577*d62bc4baSyz 	/*
578*d62bc4baSyz 	 * Hold this link to prevent it from being deleted.
579*d62bc4baSyz 	 */
580*d62bc4baSyz 	err = dls_devnet_hold_tmp(divp->div_vlanid, &dlh);
581210db224Sericheng 	if (err != 0)
582210db224Sericheng 		goto failed;
583210db224Sericheng 
584*d62bc4baSyz 	if ((vid = dls_devnet_vid(dlh)) == VLAN_ID_NONE) {
585*d62bc4baSyz 		dls_devnet_rele_tmp(dlh);
586*d62bc4baSyz 		err = EINVAL;
587*d62bc4baSyz 		goto failed;
588*d62bc4baSyz 	}
589*d62bc4baSyz 
590*d62bc4baSyz 	err = dls_vlan_hold(dls_devnet_mac(dlh), vid, &dvp, B_FALSE, B_FALSE);
591*d62bc4baSyz 	if (err != 0) {
592*d62bc4baSyz 		dls_devnet_rele_tmp(dlh);
593*d62bc4baSyz 		err = EINVAL;
594*d62bc4baSyz 		goto failed;
595*d62bc4baSyz 	}
596*d62bc4baSyz 
597*d62bc4baSyz 	divp->div_linkid = dls_devnet_linkid(dlh);
598*d62bc4baSyz 	divp->div_implicit = !dls_devnet_is_explicit(dlh);
599*d62bc4baSyz 	divp->div_vid = vid;
600*d62bc4baSyz 	divp->div_force = dvp->dv_force;
601*d62bc4baSyz 
602*d62bc4baSyz 	dls_vlan_rele(dvp);
603*d62bc4baSyz 	dls_devnet_rele_tmp(dlh);
604*d62bc4baSyz 	miocack(q, mp, sizeof (dld_ioc_vlan_attr_t), 0);
605210db224Sericheng 	return;
606210db224Sericheng 
607210db224Sericheng failed:
608210db224Sericheng 	miocnak(q, mp, 0, err);
609210db224Sericheng }
610210db224Sericheng 
611f4b3ec61Sdh /*
612*d62bc4baSyz  * DLDIOC_RENAME.
613*d62bc4baSyz  *
614*d62bc4baSyz  * This function handles two cases of link renaming. See more in comments above
615*d62bc4baSyz  * dls_datalink_rename().
616f4b3ec61Sdh  */
617f4b3ec61Sdh static void
618*d62bc4baSyz drv_ioc_rename(dld_ctl_str_t *ctls, mblk_t *mp)
619f4b3ec61Sdh {
620*d62bc4baSyz 	dld_ioc_rename_t	*dir;
621*d62bc4baSyz 	mod_hash_key_t		key;
622*d62bc4baSyz 	mod_hash_val_t		val;
623*d62bc4baSyz 	int			err;
624*d62bc4baSyz 	queue_t			*q = ctls->cs_wq;
625*d62bc4baSyz 
626*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_rename_t))) != 0)
627*d62bc4baSyz 		goto done;
628*d62bc4baSyz 
629*d62bc4baSyz 	dir = (dld_ioc_rename_t *)mp->b_cont->b_rptr;
630*d62bc4baSyz 	if ((err = dls_devnet_rename(dir->dir_linkid1, dir->dir_linkid2,
631*d62bc4baSyz 	    dir->dir_link)) != 0) {
632*d62bc4baSyz 		goto done;
633*d62bc4baSyz 	}
634*d62bc4baSyz 
635*d62bc4baSyz 	if (dir->dir_linkid2 == DATALINK_INVALID_LINKID)
636*d62bc4baSyz 		goto done;
637*d62bc4baSyz 
638*d62bc4baSyz 	/*
639*d62bc4baSyz 	 * if dir_linkid2 is not DATALINK_INVALID_LINKID, it means this
640*d62bc4baSyz 	 * renaming request is to rename a valid physical link (dir_linkid1)
641*d62bc4baSyz 	 * to a "removed" physical link (dir_linkid2, which is removed by DR
642*d62bc4baSyz 	 * or during system shutdown). In this case, the link (specified by
643*d62bc4baSyz 	 * dir_linkid1) would inherit all the configuration of dir_linkid2,
644*d62bc4baSyz 	 * and dir_linkid1 and its configuration would be lost.
645*d62bc4baSyz 	 *
646*d62bc4baSyz 	 * Remove per-link autopush configuration of dir_linkid1 in this case.
647*d62bc4baSyz 	 */
648*d62bc4baSyz 	key = (mod_hash_key_t)(uintptr_t)dir->dir_linkid1;
649*d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_WRITER);
650*d62bc4baSyz 	if (mod_hash_find(dld_ap_hashp, key, &val) != 0) {
651*d62bc4baSyz 		rw_exit(&dld_ap_hash_lock);
652*d62bc4baSyz 		goto done;
653*d62bc4baSyz 	}
654*d62bc4baSyz 
655*d62bc4baSyz 	VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0);
656*d62bc4baSyz 	kmem_free(val, sizeof (dld_ap_t));
657*d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
658*d62bc4baSyz 
659*d62bc4baSyz done:
660*d62bc4baSyz 	if (err == 0)
661*d62bc4baSyz 		miocack(q, mp, 0, 0);
662*d62bc4baSyz 	else
663*d62bc4baSyz 		miocnak(q, mp, 0, err);
664*d62bc4baSyz }
665*d62bc4baSyz 
666*d62bc4baSyz /*
667*d62bc4baSyz  * DLDIOC_SETAUTOPUSH
668*d62bc4baSyz  */
669*d62bc4baSyz static void
670*d62bc4baSyz drv_ioc_setap(dld_ctl_str_t *ctls, mblk_t *mp)
671*d62bc4baSyz {
672*d62bc4baSyz 	dld_ioc_ap_t	*diap;
673*d62bc4baSyz 	dld_ap_t	*dap;
674*d62bc4baSyz 	int		i, err;
675f4b3ec61Sdh 	queue_t		*q = ctls->cs_wq;
676*d62bc4baSyz 	mod_hash_key_t	key;
677*d62bc4baSyz 
678*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_ap_t))) != 0)
679789e0dbbSdh 		goto failed;
680789e0dbbSdh 
681*d62bc4baSyz 	diap = (dld_ioc_ap_t *)mp->b_cont->b_rptr;
682*d62bc4baSyz 	if (diap->dia_npush == 0 || diap->dia_npush > MAXAPUSH) {
683*d62bc4baSyz 		err = EINVAL;
684*d62bc4baSyz 		goto failed;
685*d62bc4baSyz 	}
686f4b3ec61Sdh 
687789e0dbbSdh 	/*
688*d62bc4baSyz 	 * Validate that the specified list of modules exist.
689789e0dbbSdh 	 */
690*d62bc4baSyz 	for (i = 0; i < diap->dia_npush; i++) {
691*d62bc4baSyz 		if (fmodsw_find(diap->dia_aplist[i], FMODSW_LOAD) == NULL) {
692*d62bc4baSyz 			err = EINVAL;
693*d62bc4baSyz 			goto failed;
694*d62bc4baSyz 		}
695*d62bc4baSyz 	}
696*d62bc4baSyz 
697*d62bc4baSyz 	key = (mod_hash_key_t)(uintptr_t)diap->dia_linkid;
698789e0dbbSdh 
699*d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_WRITER);
700*d62bc4baSyz 	if (mod_hash_find(dld_ap_hashp, key, (mod_hash_val_t *)&dap) != 0) {
701*d62bc4baSyz 		dap = kmem_zalloc(sizeof (dld_ap_t), KM_NOSLEEP);
702*d62bc4baSyz 		if (dap == NULL) {
703*d62bc4baSyz 			rw_exit(&dld_ap_hash_lock);
704*d62bc4baSyz 			err = ENOMEM;
705789e0dbbSdh 			goto failed;
706*d62bc4baSyz 		}
707*d62bc4baSyz 
708*d62bc4baSyz 		dap->da_linkid = diap->dia_linkid;
709*d62bc4baSyz 		err = mod_hash_insert(dld_ap_hashp, key, (mod_hash_val_t)dap);
710*d62bc4baSyz 		ASSERT(err == 0);
711f4b3ec61Sdh 	}
712f4b3ec61Sdh 
713*d62bc4baSyz 	/*
714*d62bc4baSyz 	 * Update the configuration.
715*d62bc4baSyz 	 */
716*d62bc4baSyz 	dap->da_anchor = diap->dia_anchor;
717*d62bc4baSyz 	dap->da_npush = diap->dia_npush;
718*d62bc4baSyz 	for (i = 0; i < diap->dia_npush; i++) {
719*d62bc4baSyz 		(void) strlcpy(dap->da_aplist[i], diap->dia_aplist[i],
720*d62bc4baSyz 		    FMNAMESZ + 1);
721*d62bc4baSyz 	}
722*d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
723789e0dbbSdh 
724*d62bc4baSyz 	miocack(q, mp, 0, 0);
725*d62bc4baSyz 	return;
726*d62bc4baSyz 
727*d62bc4baSyz failed:
728*d62bc4baSyz 	miocnak(q, mp, 0, err);
729*d62bc4baSyz }
730*d62bc4baSyz 
731*d62bc4baSyz /*
732*d62bc4baSyz  * DLDIOC_GETAUTOPUSH
733*d62bc4baSyz  */
734*d62bc4baSyz static void
735*d62bc4baSyz drv_ioc_getap(dld_ctl_str_t *ctls, mblk_t *mp)
736*d62bc4baSyz {
737*d62bc4baSyz 	dld_ioc_ap_t	*diap;
738*d62bc4baSyz 	dld_ap_t	*dap;
739*d62bc4baSyz 	int		i, err;
740*d62bc4baSyz 	queue_t		*q = ctls->cs_wq;
741*d62bc4baSyz 
742*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_ap_t))) != 0)
743789e0dbbSdh 		goto failed;
744789e0dbbSdh 
745*d62bc4baSyz 	diap = (dld_ioc_ap_t *)mp->b_cont->b_rptr;
746*d62bc4baSyz 
747*d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_READER);
748*d62bc4baSyz 	if (mod_hash_find(dld_ap_hashp,
749*d62bc4baSyz 	    (mod_hash_key_t)(uintptr_t)diap->dia_linkid,
750*d62bc4baSyz 	    (mod_hash_val_t *)&dap) != 0) {
751*d62bc4baSyz 		err = ENOENT;
752*d62bc4baSyz 		rw_exit(&dld_ap_hash_lock);
753789e0dbbSdh 		goto failed;
754f595a68aSyz 	}
755*d62bc4baSyz 
756*d62bc4baSyz 	/*
757*d62bc4baSyz 	 * Retrieve the configuration.
758*d62bc4baSyz 	 */
759*d62bc4baSyz 	diap->dia_anchor = dap->da_anchor;
760*d62bc4baSyz 	diap->dia_npush = dap->da_npush;
761*d62bc4baSyz 	for (i = 0; i < dap->da_npush; i++) {
762*d62bc4baSyz 		(void) strlcpy(diap->dia_aplist[i], dap->da_aplist[i],
763*d62bc4baSyz 		    FMNAMESZ + 1);
764*d62bc4baSyz 	}
765*d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
766*d62bc4baSyz 
767*d62bc4baSyz 	miocack(q, mp, sizeof (dld_ioc_ap_t), 0);
768*d62bc4baSyz 	return;
769*d62bc4baSyz 
770789e0dbbSdh failed:
771789e0dbbSdh 	miocnak(q, mp, 0, err);
772f4b3ec61Sdh }
773f4b3ec61Sdh 
774f4b3ec61Sdh /*
775*d62bc4baSyz  * DLDIOC_CLRAUTOPUSH
776f4b3ec61Sdh  */
777f4b3ec61Sdh static void
778*d62bc4baSyz drv_ioc_clrap(dld_ctl_str_t *ctls, mblk_t *mp)
779f4b3ec61Sdh {
780*d62bc4baSyz 	dld_ioc_ap_t	*diap;
781*d62bc4baSyz 	mod_hash_val_t	val;
782*d62bc4baSyz 	mod_hash_key_t	key;
783f4b3ec61Sdh 	int		err;
784*d62bc4baSyz 	queue_t		*q = ctls->cs_wq;
785f4b3ec61Sdh 
786*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_ap_t))) != 0)
787*d62bc4baSyz 		goto done;
788f4b3ec61Sdh 
789*d62bc4baSyz 	diap = (dld_ioc_ap_t *)mp->b_cont->b_rptr;
790*d62bc4baSyz 	key = (mod_hash_key_t)(uintptr_t)diap->dia_linkid;
791f4b3ec61Sdh 
792*d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_WRITER);
793*d62bc4baSyz 	if (mod_hash_find(dld_ap_hashp, key, &val) != 0) {
794*d62bc4baSyz 		rw_exit(&dld_ap_hash_lock);
795*d62bc4baSyz 		goto done;
796f4b3ec61Sdh 	}
797f4b3ec61Sdh 
798*d62bc4baSyz 	VERIFY(mod_hash_remove(dld_ap_hashp, key, &val) == 0);
799*d62bc4baSyz 	kmem_free(val, sizeof (dld_ap_t));
800*d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
801*d62bc4baSyz 
802*d62bc4baSyz done:
803*d62bc4baSyz 	if (err == 0)
804*d62bc4baSyz 		miocack(q, mp, 0, 0);
805*d62bc4baSyz 	else
806*d62bc4baSyz 		miocnak(q, mp, 0, err);
807f4b3ec61Sdh }
808f4b3ec61Sdh 
809f4b3ec61Sdh /*
810*d62bc4baSyz  * DLDIOC_DOORSERVER
811f4b3ec61Sdh  */
812f4b3ec61Sdh static void
813*d62bc4baSyz drv_ioc_doorserver(dld_ctl_str_t *ctls, mblk_t *mp)
814f4b3ec61Sdh {
815f4b3ec61Sdh 	queue_t		*q = ctls->cs_wq;
816*d62bc4baSyz 	dld_ioc_door_t	*did;
817f4b3ec61Sdh 	int		err;
818f4b3ec61Sdh 
819*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_door_t))) != 0)
820*d62bc4baSyz 		goto done;
821*d62bc4baSyz 
822*d62bc4baSyz 	did = (dld_ioc_door_t *)mp->b_cont->b_rptr;
823*d62bc4baSyz 	err = dls_mgmt_door_set(did->did_start_door);
824*d62bc4baSyz 
825*d62bc4baSyz done:
826*d62bc4baSyz 	if (err == 0)
827*d62bc4baSyz 		miocack(q, mp, 0, 0);
828*d62bc4baSyz 	else
829f4b3ec61Sdh 		miocnak(q, mp, 0, err);
830*d62bc4baSyz }
831*d62bc4baSyz 
832*d62bc4baSyz /*
833*d62bc4baSyz  * DLDIOC_SETZID
834*d62bc4baSyz  */
835*d62bc4baSyz static void
836*d62bc4baSyz drv_ioc_setzid(dld_ctl_str_t *ctls, mblk_t *mp)
837*d62bc4baSyz {
838*d62bc4baSyz 	queue_t			*q = ctls->cs_wq;
839*d62bc4baSyz 	dld_ioc_setzid_t	*dis;
840*d62bc4baSyz 	int			err;
841*d62bc4baSyz 
842*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_setzid_t))) != 0)
843*d62bc4baSyz 		goto done;
844f4b3ec61Sdh 
845*d62bc4baSyz 	dis = (dld_ioc_setzid_t *)mp->b_cont->b_rptr;
846*d62bc4baSyz 	err = dls_devnet_setzid(dis->dis_link, dis->dis_zid);
847*d62bc4baSyz 
848*d62bc4baSyz done:
849*d62bc4baSyz 	if (err == 0)
850*d62bc4baSyz 		miocack(q, mp, 0, 0);
851*d62bc4baSyz 	else
852f4b3ec61Sdh 		miocnak(q, mp, 0, err);
853*d62bc4baSyz }
854*d62bc4baSyz 
855*d62bc4baSyz /*
856*d62bc4baSyz  * DLDIOC_GETZID
857*d62bc4baSyz  */
858*d62bc4baSyz static void
859*d62bc4baSyz drv_ioc_getzid(dld_ctl_str_t *ctls, mblk_t *mp)
860*d62bc4baSyz {
861*d62bc4baSyz 	queue_t			*q = ctls->cs_wq;
862*d62bc4baSyz 	dld_ioc_getzid_t	*dig;
863*d62bc4baSyz 	int			err;
864*d62bc4baSyz 
865*d62bc4baSyz 	if ((err = miocpullup(mp, sizeof (dld_ioc_getzid_t))) != 0)
866*d62bc4baSyz 		goto done;
867*d62bc4baSyz 
868*d62bc4baSyz 	dig = (dld_ioc_getzid_t *)mp->b_cont->b_rptr;
869*d62bc4baSyz 	err = dls_devnet_getzid(dig->dig_linkid, &dig->dig_zid);
870*d62bc4baSyz 
871*d62bc4baSyz done:
872*d62bc4baSyz 	if (err == 0)
873*d62bc4baSyz 		miocack(q, mp, sizeof (dld_ioc_getzid_t), 0);
874f4b3ec61Sdh 	else
875*d62bc4baSyz 		miocnak(q, mp, 0, err);
876f4b3ec61Sdh }
877210db224Sericheng 
878210db224Sericheng /*
879210db224Sericheng  * Process an IOCTL message received by the control node.
880210db224Sericheng  */
881210db224Sericheng static void
882210db224Sericheng drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp)
883210db224Sericheng {
884210db224Sericheng 	uint_t	cmd;
885210db224Sericheng 
886210db224Sericheng 	cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
887210db224Sericheng 	switch (cmd) {
888*d62bc4baSyz 	case DLDIOC_ATTR:
889210db224Sericheng 		drv_ioc_attr(ctls, mp);
890210db224Sericheng 		return;
891*d62bc4baSyz 	case DLDIOC_PHYS_ATTR:
892*d62bc4baSyz 		drv_ioc_phys_attr(ctls, mp);
8937c478bd9Sstevel@tonic-gate 		return;
894*d62bc4baSyz 	case DLDIOC_SECOBJ_SET:
8950ba2cbe9Sxc 		drv_ioc_secobj_set(ctls, mp);
8960ba2cbe9Sxc 		return;
897*d62bc4baSyz 	case DLDIOC_SECOBJ_GET:
8980ba2cbe9Sxc 		drv_ioc_secobj_get(ctls, mp);
8990ba2cbe9Sxc 		return;
900*d62bc4baSyz 	case DLDIOC_SECOBJ_UNSET:
9010ba2cbe9Sxc 		drv_ioc_secobj_unset(ctls, mp);
9020ba2cbe9Sxc 		return;
903*d62bc4baSyz 	case DLDIOC_CREATE_VLAN:
904*d62bc4baSyz 		drv_ioc_create_vlan(ctls, mp);
905*d62bc4baSyz 		return;
906*d62bc4baSyz 	case DLDIOC_DELETE_VLAN:
907*d62bc4baSyz 		drv_ioc_delete_vlan(ctls, mp);
908*d62bc4baSyz 		return;
909*d62bc4baSyz 	case DLDIOC_VLAN_ATTR:
910*d62bc4baSyz 		drv_ioc_vlan_attr(ctls, mp);
911*d62bc4baSyz 		return;
912*d62bc4baSyz 	case DLDIOC_SETAUTOPUSH:
913*d62bc4baSyz 		drv_ioc_setap(ctls, mp);
914*d62bc4baSyz 		return;
915*d62bc4baSyz 	case DLDIOC_GETAUTOPUSH:
916*d62bc4baSyz 		drv_ioc_getap(ctls, mp);
917*d62bc4baSyz 		return;
918*d62bc4baSyz 	case DLDIOC_CLRAUTOPUSH:
919*d62bc4baSyz 		drv_ioc_clrap(ctls, mp);
920f4b3ec61Sdh 		return;
921*d62bc4baSyz 	case DLDIOC_DOORSERVER:
922*d62bc4baSyz 		drv_ioc_doorserver(ctls, mp);
923f4b3ec61Sdh 		return;
924*d62bc4baSyz 	case DLDIOC_SETZID:
925*d62bc4baSyz 		drv_ioc_setzid(ctls, mp);
926*d62bc4baSyz 		return;
927*d62bc4baSyz 	case DLDIOC_GETZID:
928*d62bc4baSyz 		drv_ioc_getzid(ctls, mp);
929*d62bc4baSyz 		return;
930*d62bc4baSyz 	case DLDIOC_RENAME:
931*d62bc4baSyz 		drv_ioc_rename(ctls, mp);
932f4b3ec61Sdh 		return;
933210db224Sericheng 	default:
934210db224Sericheng 		miocnak(ctls->cs_wq, mp, 0, ENOTSUP);
935210db224Sericheng 		return;
936210db224Sericheng 	}
937210db224Sericheng }
9387c478bd9Sstevel@tonic-gate 
939210db224Sericheng /*
940210db224Sericheng  * Write side put routine of the dld control node.
941210db224Sericheng  */
942210db224Sericheng static void
943210db224Sericheng drv_uw_put(queue_t *q, mblk_t *mp)
944210db224Sericheng {
945210db224Sericheng 	dld_ctl_str_t *ctls = q->q_ptr;
946210db224Sericheng 
947210db224Sericheng 	switch (mp->b_datap->db_type) {
948210db224Sericheng 	case M_IOCTL:
949210db224Sericheng 		drv_ioc(ctls, mp);
950210db224Sericheng 		break;
951210db224Sericheng 	default:
952210db224Sericheng 		freemsg(mp);
953210db224Sericheng 		break;
954210db224Sericheng 	}
955210db224Sericheng }
956210db224Sericheng 
957210db224Sericheng /*
958210db224Sericheng  * Write-side service procedure.
959210db224Sericheng  */
960210db224Sericheng void
961210db224Sericheng drv_uw_srv(queue_t *q)
962210db224Sericheng {
963210db224Sericheng 	mblk_t *mp;
964210db224Sericheng 
965210db224Sericheng 	while (mp = getq(q))
966210db224Sericheng 		drv_uw_put(q, mp);
9677c478bd9Sstevel@tonic-gate }
9680ba2cbe9Sxc 
969*d62bc4baSyz /*
970*d62bc4baSyz  * Check for GLDv3 autopush information.  There are three cases:
971*d62bc4baSyz  *
972*d62bc4baSyz  *   1. If devp points to a GLDv3 datalink and it has autopush configuration,
973*d62bc4baSyz  *	fill dlap in with that information and return 0.
974*d62bc4baSyz  *
975*d62bc4baSyz  *   2. If devp points to a GLDv3 datalink but it doesn't have autopush
976*d62bc4baSyz  *	configuration, then replace devp with the physical device (if one
977*d62bc4baSyz  *	exists) and return 1.  This allows stropen() to find the old-school
978*d62bc4baSyz  *	per-driver autopush configuration.  (For softmac, the result is that
979*d62bc4baSyz  *	the softmac dev_t is replaced with the legacy device's dev_t).
980*d62bc4baSyz  *
981*d62bc4baSyz  *   3. If neither of the above apply, don't touch the args and return -1.
982*d62bc4baSyz  */
983*d62bc4baSyz int
984*d62bc4baSyz dld_autopush(dev_t *devp, struct dlautopush *dlap)
985*d62bc4baSyz {
986*d62bc4baSyz 	dld_ap_t	*dap;
987*d62bc4baSyz 	datalink_id_t	linkid;
988*d62bc4baSyz 	dev_t		phydev;
989*d62bc4baSyz 
990*d62bc4baSyz 	if (!GLDV3_DRV(getmajor(*devp)))
991*d62bc4baSyz 		return (-1);
992*d62bc4baSyz 
993*d62bc4baSyz 	/*
994*d62bc4baSyz 	 * Find the linkid by the link's dev_t.
995*d62bc4baSyz 	 */
996*d62bc4baSyz 	if (dls_devnet_dev2linkid(*devp, &linkid) != 0)
997*d62bc4baSyz 		return (-1);
998*d62bc4baSyz 
999*d62bc4baSyz 	/*
1000*d62bc4baSyz 	 * Find the autopush configuration associated with the linkid.
1001*d62bc4baSyz 	 */
1002*d62bc4baSyz 	rw_enter(&dld_ap_hash_lock, RW_READER);
1003*d62bc4baSyz 	if (mod_hash_find(dld_ap_hashp, (mod_hash_key_t)(uintptr_t)linkid,
1004*d62bc4baSyz 	    (mod_hash_val_t *)&dap) == 0) {
1005*d62bc4baSyz 		*dlap = dap->da_ap;
1006*d62bc4baSyz 		rw_exit(&dld_ap_hash_lock);
1007*d62bc4baSyz 		return (0);
1008*d62bc4baSyz 	}
1009*d62bc4baSyz 	rw_exit(&dld_ap_hash_lock);
1010*d62bc4baSyz 
1011*d62bc4baSyz 	if (dls_devnet_phydev(linkid, &phydev) != 0)
1012*d62bc4baSyz 		return (-1);
1013*d62bc4baSyz 
1014*d62bc4baSyz 	*devp = phydev;
1015*d62bc4baSyz 	return (1);
1016*d62bc4baSyz }
1017*d62bc4baSyz 
10180ba2cbe9Sxc /*
10190ba2cbe9Sxc  * Secure objects implementation
10200ba2cbe9Sxc  */
10210ba2cbe9Sxc 
10220ba2cbe9Sxc /* ARGSUSED */
10230ba2cbe9Sxc static int
10240ba2cbe9Sxc drv_secobj_ctor(void *buf, void *arg, int kmflag)
10250ba2cbe9Sxc {
10260ba2cbe9Sxc 	bzero(buf, sizeof (dld_secobj_t));
10270ba2cbe9Sxc 	return (0);
10280ba2cbe9Sxc }
10290ba2cbe9Sxc 
10300ba2cbe9Sxc static void
10310ba2cbe9Sxc drv_secobj_init(void)
10320ba2cbe9Sxc {
10330ba2cbe9Sxc 	rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL);
10340ba2cbe9Sxc 	drv_secobj_cachep = kmem_cache_create("drv_secobj_cache",
10350ba2cbe9Sxc 	    sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL,
10360ba2cbe9Sxc 	    NULL, NULL, NULL, 0);
10370ba2cbe9Sxc 	drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash",
10380ba2cbe9Sxc 	    SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
10390ba2cbe9Sxc 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
10400ba2cbe9Sxc }
10410ba2cbe9Sxc 
10420ba2cbe9Sxc static void
10430ba2cbe9Sxc drv_secobj_fini(void)
10440ba2cbe9Sxc {
10450ba2cbe9Sxc 	mod_hash_destroy_hash(drv_secobj_hash);
10460ba2cbe9Sxc 	kmem_cache_destroy(drv_secobj_cachep);
10470ba2cbe9Sxc 	rw_destroy(&drv_secobj_lock);
10480ba2cbe9Sxc }
10490ba2cbe9Sxc 
10500ba2cbe9Sxc static void
10510ba2cbe9Sxc drv_ioc_secobj_set(dld_ctl_str_t *ctls, mblk_t *mp)
10520ba2cbe9Sxc {
10530ba2cbe9Sxc 	dld_ioc_secobj_set_t	*ssp;
10540ba2cbe9Sxc 	dld_secobj_t		*sobjp, *objp;
10550ba2cbe9Sxc 	int			err = EINVAL;
10560ba2cbe9Sxc 	queue_t			*q = ctls->cs_wq;
10570ba2cbe9Sxc 
10580ba2cbe9Sxc 	if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_set_t))) != 0)
10590ba2cbe9Sxc 		goto failed;
10600ba2cbe9Sxc 
10610ba2cbe9Sxc 	ssp = (dld_ioc_secobj_set_t *)mp->b_cont->b_rptr;
10620ba2cbe9Sxc 	sobjp = &ssp->ss_obj;
10630ba2cbe9Sxc 
1064a399b765Szf 	if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP &&
1065a399b765Szf 	    sobjp->so_class != DLD_SECOBJ_CLASS_WPA)
10660ba2cbe9Sxc 		goto failed;
10670ba2cbe9Sxc 
10680ba2cbe9Sxc 	if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' ||
10690ba2cbe9Sxc 	    sobjp->so_len > DLD_SECOBJ_VAL_MAX)
10700ba2cbe9Sxc 		goto failed;
10710ba2cbe9Sxc 
10720ba2cbe9Sxc 	rw_enter(&drv_secobj_lock, RW_WRITER);
10730ba2cbe9Sxc 	err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name,
10740ba2cbe9Sxc 	    (mod_hash_val_t *)&objp);
10750ba2cbe9Sxc 	if (err == 0) {
10760ba2cbe9Sxc 		if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) {
10770ba2cbe9Sxc 			err = EEXIST;
10780ba2cbe9Sxc 			rw_exit(&drv_secobj_lock);
10790ba2cbe9Sxc 			goto failed;
10800ba2cbe9Sxc 		}
10810ba2cbe9Sxc 	} else {
10820ba2cbe9Sxc 		ASSERT(err == MH_ERR_NOTFOUND);
10830ba2cbe9Sxc 		if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) {
10840ba2cbe9Sxc 			err = ENOENT;
10850ba2cbe9Sxc 			rw_exit(&drv_secobj_lock);
10860ba2cbe9Sxc 			goto failed;
10870ba2cbe9Sxc 		}
10880ba2cbe9Sxc 		objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP);
10890ba2cbe9Sxc 		(void) strlcpy(objp->so_name, sobjp->so_name,
10900ba2cbe9Sxc 		    DLD_SECOBJ_NAME_MAX);
10910ba2cbe9Sxc 
10920ba2cbe9Sxc 		err = mod_hash_insert(drv_secobj_hash,
10930ba2cbe9Sxc 		    (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp);
10940ba2cbe9Sxc 		ASSERT(err == 0);
10950ba2cbe9Sxc 	}
10960ba2cbe9Sxc 	bcopy(sobjp->so_val, objp->so_val, sobjp->so_len);
10970ba2cbe9Sxc 	objp->so_len = sobjp->so_len;
10980ba2cbe9Sxc 	objp->so_class = sobjp->so_class;
10990ba2cbe9Sxc 	rw_exit(&drv_secobj_lock);
11000ba2cbe9Sxc 	miocack(q, mp, 0, 0);
11010ba2cbe9Sxc 	return;
11020ba2cbe9Sxc 
11030ba2cbe9Sxc failed:
11040ba2cbe9Sxc 	ASSERT(err != 0);
11050ba2cbe9Sxc 	miocnak(q, mp, 0, err);
11060ba2cbe9Sxc }
11070ba2cbe9Sxc 
11080ba2cbe9Sxc typedef struct dld_secobj_state {
11090ba2cbe9Sxc 	uint_t		ss_free;
11100ba2cbe9Sxc 	uint_t		ss_count;
11110ba2cbe9Sxc 	int		ss_rc;
11120ba2cbe9Sxc 	dld_secobj_t	*ss_objp;
11130ba2cbe9Sxc } dld_secobj_state_t;
11140ba2cbe9Sxc 
11150ba2cbe9Sxc /* ARGSUSED */
11160ba2cbe9Sxc static uint_t
11170ba2cbe9Sxc drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
11180ba2cbe9Sxc {
11190ba2cbe9Sxc 	dld_secobj_state_t	*statep = arg;
11200ba2cbe9Sxc 	dld_secobj_t		*sobjp = (dld_secobj_t *)val;
11210ba2cbe9Sxc 
11220ba2cbe9Sxc 	if (statep->ss_free < sizeof (dld_secobj_t)) {
11230ba2cbe9Sxc 		statep->ss_rc = ENOSPC;
11240ba2cbe9Sxc 		return (MH_WALK_TERMINATE);
11250ba2cbe9Sxc 	}
11260ba2cbe9Sxc 	bcopy(sobjp, statep->ss_objp, sizeof (dld_secobj_t));
11270ba2cbe9Sxc 	statep->ss_objp++;
11280ba2cbe9Sxc 	statep->ss_free -= sizeof (dld_secobj_t);
11290ba2cbe9Sxc 	statep->ss_count++;
11300ba2cbe9Sxc 	return (MH_WALK_CONTINUE);
11310ba2cbe9Sxc }
11320ba2cbe9Sxc 
11330ba2cbe9Sxc static void
11340ba2cbe9Sxc drv_ioc_secobj_get(dld_ctl_str_t *ctls, mblk_t *mp)
11350ba2cbe9Sxc {
11360ba2cbe9Sxc 	dld_ioc_secobj_get_t	*sgp;
11370ba2cbe9Sxc 	dld_secobj_t		*sobjp, *objp;
11380ba2cbe9Sxc 	int			err = EINVAL;
11390ba2cbe9Sxc 	uint_t			extra = 0;
11400ba2cbe9Sxc 	queue_t			*q = ctls->cs_wq;
11410ba2cbe9Sxc 	mblk_t			*bp;
11420ba2cbe9Sxc 
11430ba2cbe9Sxc 	if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_get_t))) != 0)
11440ba2cbe9Sxc 		goto failed;
11450ba2cbe9Sxc 
11460ba2cbe9Sxc 	if ((bp = msgpullup(mp->b_cont, -1)) == NULL)
11470ba2cbe9Sxc 		goto failed;
11480ba2cbe9Sxc 
11490ba2cbe9Sxc 	freemsg(mp->b_cont);
11500ba2cbe9Sxc 	mp->b_cont = bp;
11510ba2cbe9Sxc 	sgp = (dld_ioc_secobj_get_t *)bp->b_rptr;
11520ba2cbe9Sxc 	sobjp = &sgp->sg_obj;
11530ba2cbe9Sxc 
11540ba2cbe9Sxc 	if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0')
11550ba2cbe9Sxc 		goto failed;
11560ba2cbe9Sxc 
11570ba2cbe9Sxc 	rw_enter(&drv_secobj_lock, RW_READER);
11580ba2cbe9Sxc 	if (sobjp->so_name[0] != '\0') {
11590ba2cbe9Sxc 		err = mod_hash_find(drv_secobj_hash,
11600ba2cbe9Sxc 		    (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp);
11610ba2cbe9Sxc 		if (err != 0) {
11620ba2cbe9Sxc 			ASSERT(err == MH_ERR_NOTFOUND);
11630ba2cbe9Sxc 			err = ENOENT;
11640ba2cbe9Sxc 			rw_exit(&drv_secobj_lock);
11650ba2cbe9Sxc 			goto failed;
11660ba2cbe9Sxc 		}
11670ba2cbe9Sxc 		bcopy(objp->so_val, sobjp->so_val, objp->so_len);
11680ba2cbe9Sxc 		sobjp->so_len = objp->so_len;
11690ba2cbe9Sxc 		sobjp->so_class = objp->so_class;
11700ba2cbe9Sxc 		sgp->sg_count = 1;
11710ba2cbe9Sxc 	} else {
11720ba2cbe9Sxc 		dld_secobj_state_t	state;
11730ba2cbe9Sxc 
11740ba2cbe9Sxc 		state.ss_free = MBLKL(bp) - sizeof (dld_ioc_secobj_get_t);
11750ba2cbe9Sxc 		state.ss_count = 0;
11760ba2cbe9Sxc 		state.ss_rc = 0;
11770ba2cbe9Sxc 		state.ss_objp = (dld_secobj_t *)(sgp + 1);
11780ba2cbe9Sxc 		mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state);
11790ba2cbe9Sxc 		if (state.ss_rc != 0) {
11800ba2cbe9Sxc 			err = state.ss_rc;
11810ba2cbe9Sxc 			rw_exit(&drv_secobj_lock);
11820ba2cbe9Sxc 			goto failed;
11830ba2cbe9Sxc 		}
11840ba2cbe9Sxc 		sgp->sg_count = state.ss_count;
11850ba2cbe9Sxc 		extra = state.ss_count * sizeof (dld_secobj_t);
11860ba2cbe9Sxc 	}
11870ba2cbe9Sxc 	rw_exit(&drv_secobj_lock);
11880ba2cbe9Sxc 	miocack(q, mp, sizeof (dld_ioc_secobj_get_t) + extra, 0);
11890ba2cbe9Sxc 	return;
11900ba2cbe9Sxc 
11910ba2cbe9Sxc failed:
11920ba2cbe9Sxc 	ASSERT(err != 0);
11930ba2cbe9Sxc 	miocnak(q, mp, 0, err);
11940ba2cbe9Sxc 
11950ba2cbe9Sxc }
11960ba2cbe9Sxc 
11970ba2cbe9Sxc static void
11980ba2cbe9Sxc drv_ioc_secobj_unset(dld_ctl_str_t *ctls, mblk_t *mp)
11990ba2cbe9Sxc {
12000ba2cbe9Sxc 	dld_ioc_secobj_unset_t	*sup;
12010ba2cbe9Sxc 	dld_secobj_t		*objp;
12020ba2cbe9Sxc 	mod_hash_val_t		val;
12030ba2cbe9Sxc 	int			err = EINVAL;
12040ba2cbe9Sxc 	queue_t			*q = ctls->cs_wq;
12050ba2cbe9Sxc 
12060ba2cbe9Sxc 	if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_unset_t))) != 0)
12070ba2cbe9Sxc 		goto failed;
12080ba2cbe9Sxc 
12090ba2cbe9Sxc 	sup = (dld_ioc_secobj_unset_t *)mp->b_cont->b_rptr;
12100ba2cbe9Sxc 	if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0')
12110ba2cbe9Sxc 		goto failed;
12120ba2cbe9Sxc 
12130ba2cbe9Sxc 	rw_enter(&drv_secobj_lock, RW_WRITER);
12140ba2cbe9Sxc 	err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name,
12150ba2cbe9Sxc 	    (mod_hash_val_t *)&objp);
12160ba2cbe9Sxc 	if (err != 0) {
12170ba2cbe9Sxc 		ASSERT(err == MH_ERR_NOTFOUND);
12180ba2cbe9Sxc 		err = ENOENT;
12190ba2cbe9Sxc 		rw_exit(&drv_secobj_lock);
12200ba2cbe9Sxc 		goto failed;
12210ba2cbe9Sxc 	}
12220ba2cbe9Sxc 	err = mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name,
12230ba2cbe9Sxc 	    (mod_hash_val_t *)&val);
12240ba2cbe9Sxc 	ASSERT(err == 0);
12250ba2cbe9Sxc 	ASSERT(objp == (dld_secobj_t *)val);
12260ba2cbe9Sxc 
12270ba2cbe9Sxc 	kmem_cache_free(drv_secobj_cachep, objp);
12280ba2cbe9Sxc 	rw_exit(&drv_secobj_lock);
12290ba2cbe9Sxc 	miocack(q, mp, 0, 0);
12300ba2cbe9Sxc 	return;
12310ba2cbe9Sxc 
12320ba2cbe9Sxc failed:
12330ba2cbe9Sxc 	ASSERT(err != 0);
12340ba2cbe9Sxc 	miocnak(q, mp, 0, err);
12350ba2cbe9Sxc }
1236