xref: /onnv-gate/usr/src/uts/common/io/dld/dld_drv.c (revision 4126:31652d91f33e)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52311Sseb  * Common Development and Distribution License (the "License").
62311Sseb  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
223448Sdh155122  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Data-Link Driver
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include	<sys/conf.h>
33269Sericheng #include	<sys/mkdev.h>
34269Sericheng #include	<sys/modctl.h>
350Sstevel@tonic-gate #include	<sys/stat.h>
36269Sericheng #include	<sys/strsun.h>
37269Sericheng #include	<sys/dld.h>
38269Sericheng #include	<sys/dld_impl.h>
39269Sericheng #include	<sys/dls_impl.h>
403448Sdh155122 #include 	<sys/vlan.h>
410Sstevel@tonic-gate #include	<inet/common.h>
420Sstevel@tonic-gate 
43269Sericheng /*
44269Sericheng  * dld control node state, one per open control node session.
45269Sericheng  */
46269Sericheng typedef struct dld_ctl_str_s {
47269Sericheng 	minor_t cs_minor;
48269Sericheng 	queue_t *cs_wq;
49269Sericheng } dld_ctl_str_t;
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static void	drv_init(void);
520Sstevel@tonic-gate static int	drv_fini(void);
530Sstevel@tonic-gate 
540Sstevel@tonic-gate static int	drv_getinfo(dev_info_t	*, ddi_info_cmd_t, void *, void **);
550Sstevel@tonic-gate static int	drv_attach(dev_info_t *, ddi_attach_cmd_t);
560Sstevel@tonic-gate static int	drv_detach(dev_info_t *, ddi_detach_cmd_t);
570Sstevel@tonic-gate 
58269Sericheng /*
593147Sxc151355  * Secure objects declarations
603147Sxc151355  */
613147Sxc151355 #define	SECOBJ_WEP_HASHSZ	67
623147Sxc151355 static krwlock_t	drv_secobj_lock;
633147Sxc151355 static kmem_cache_t	*drv_secobj_cachep;
643147Sxc151355 static mod_hash_t	*drv_secobj_hash;
653147Sxc151355 static void		drv_secobj_init(void);
663147Sxc151355 static void		drv_secobj_fini(void);
673147Sxc151355 static void		drv_ioc_secobj_set(dld_ctl_str_t *, mblk_t *);
683147Sxc151355 static void		drv_ioc_secobj_get(dld_ctl_str_t *, mblk_t *);
693147Sxc151355 static void		drv_ioc_secobj_unset(dld_ctl_str_t *, mblk_t *);
703147Sxc151355 
713147Sxc151355 /*
72269Sericheng  * The following entry points are private to dld and are used for control
73269Sericheng  * operations only. The entry points exported to mac drivers are defined
74269Sericheng  * in dld_str.c. Refer to the comment on top of dld_str.c for details.
75269Sericheng  */
760Sstevel@tonic-gate static int	drv_open(queue_t *, dev_t *, int, int, cred_t *);
770Sstevel@tonic-gate static int	drv_close(queue_t *);
780Sstevel@tonic-gate 
790Sstevel@tonic-gate static void	drv_uw_put(queue_t *, mblk_t *);
800Sstevel@tonic-gate static void	drv_uw_srv(queue_t *);
810Sstevel@tonic-gate 
820Sstevel@tonic-gate dev_info_t	*dld_dip;		/* dev_info_t for the driver */
83269Sericheng uint32_t	dld_opt = 0;		/* Global options */
84269Sericheng static vmem_t	*dld_ctl_vmem;		/* for control minor numbers */
850Sstevel@tonic-gate 
860Sstevel@tonic-gate static	struct	module_info	drv_info = {
870Sstevel@tonic-gate 	0,			/* mi_idnum */
880Sstevel@tonic-gate 	DLD_DRIVER_NAME,	/* mi_idname */
890Sstevel@tonic-gate 	0,			/* mi_minpsz */
900Sstevel@tonic-gate 	(64 * 1024),		/* mi_maxpsz */
910Sstevel@tonic-gate 	1,			/* mi_hiwat */
920Sstevel@tonic-gate 	0			/* mi_lowat */
930Sstevel@tonic-gate };
940Sstevel@tonic-gate 
950Sstevel@tonic-gate static	struct qinit		drv_ur_init = {
960Sstevel@tonic-gate 	NULL,			/* qi_putp */
970Sstevel@tonic-gate 	NULL,			/* qi_srvp */
980Sstevel@tonic-gate 	drv_open,		/* qi_qopen */
990Sstevel@tonic-gate 	drv_close,		/* qi_qclose */
1000Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
1010Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
1020Sstevel@tonic-gate 	NULL			/* qi_mstat */
1030Sstevel@tonic-gate };
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate static	struct qinit		drv_uw_init = {
1060Sstevel@tonic-gate 	(pfi_t)drv_uw_put,	/* qi_putp */
1070Sstevel@tonic-gate 	(pfi_t)drv_uw_srv,	/* qi_srvp */
1080Sstevel@tonic-gate 	NULL,			/* qi_qopen */
1090Sstevel@tonic-gate 	NULL,			/* qi_qclose */
1100Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
1110Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
1120Sstevel@tonic-gate 	NULL			/* qi_mstat */
1130Sstevel@tonic-gate };
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate static	struct streamtab	drv_stream = {
1160Sstevel@tonic-gate 	&drv_ur_init,		/* st_rdinit */
1170Sstevel@tonic-gate 	&drv_uw_init,		/* st_wrinit */
1180Sstevel@tonic-gate 	NULL,			/* st_muxrinit */
1190Sstevel@tonic-gate 	NULL			/* st_muxwinit */
1200Sstevel@tonic-gate };
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach,
123269Sericheng     nodev, drv_getinfo, D_MP, &drv_stream);
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /*
1260Sstevel@tonic-gate  * Module linkage information for the kernel.
1270Sstevel@tonic-gate  */
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate extern	struct mod_ops		mod_driverops;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate static	struct modldrv		drv_modldrv = {
1320Sstevel@tonic-gate 	&mod_driverops,
1330Sstevel@tonic-gate 	DLD_INFO,
1340Sstevel@tonic-gate 	&drv_ops
1350Sstevel@tonic-gate };
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate static	struct modlinkage	drv_modlinkage = {
1380Sstevel@tonic-gate 	MODREV_1,
1390Sstevel@tonic-gate 	&drv_modldrv,
1400Sstevel@tonic-gate 	NULL
1410Sstevel@tonic-gate };
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate int
1440Sstevel@tonic-gate _init(void)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate 	int	err;
1470Sstevel@tonic-gate 
148269Sericheng 	drv_init();
149269Sericheng 
1500Sstevel@tonic-gate 	if ((err = mod_install(&drv_modlinkage)) != 0)
1510Sstevel@tonic-gate 		return (err);
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate 	return (0);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate int
1570Sstevel@tonic-gate _fini(void)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate 	int	err;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	if ((err = mod_remove(&drv_modlinkage)) != 0)
1620Sstevel@tonic-gate 		return (err);
1630Sstevel@tonic-gate 
164269Sericheng 	if (drv_fini() != 0) {
165269Sericheng 		(void) mod_install(&drv_modlinkage);
166269Sericheng 		return (DDI_FAILURE);
167269Sericheng 	}
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	return (err);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate int
1730Sstevel@tonic-gate _info(struct modinfo *modinfop)
1740Sstevel@tonic-gate {
1750Sstevel@tonic-gate 	return (mod_info(&drv_modlinkage, modinfop));
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate /*
179269Sericheng  * Initialize component modules.
1800Sstevel@tonic-gate  */
1810Sstevel@tonic-gate static void
1820Sstevel@tonic-gate drv_init(void)
1830Sstevel@tonic-gate {
184269Sericheng 	dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1,
185269Sericheng 	    NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER);
1863147Sxc151355 	drv_secobj_init();
1870Sstevel@tonic-gate 	dld_str_init();
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate static int
1910Sstevel@tonic-gate drv_fini(void)
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate 	int	err;
1940Sstevel@tonic-gate 
195269Sericheng 	if ((err = dld_str_fini()) != 0)
1960Sstevel@tonic-gate 		return (err);
1970Sstevel@tonic-gate 
1983147Sxc151355 	drv_secobj_fini();
199269Sericheng 	vmem_destroy(dld_ctl_vmem);
2000Sstevel@tonic-gate 	return (0);
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate 
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate  * devo_getinfo: getinfo(9e)
2050Sstevel@tonic-gate  */
2060Sstevel@tonic-gate /*ARGSUSED*/
2070Sstevel@tonic-gate static int
2080Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
2090Sstevel@tonic-gate {
2100Sstevel@tonic-gate 	if (dld_dip == NULL)
2110Sstevel@tonic-gate 		return (DDI_FAILURE);
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	switch (cmd) {
2140Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2150Sstevel@tonic-gate 		*resp = (void *)0;
2160Sstevel@tonic-gate 		break;
2170Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2180Sstevel@tonic-gate 		*resp = (void *)dld_dip;
2190Sstevel@tonic-gate 		break;
2200Sstevel@tonic-gate 	default:
2210Sstevel@tonic-gate 		return (DDI_FAILURE);
2220Sstevel@tonic-gate 	}
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	return (DDI_SUCCESS);
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate /*
2280Sstevel@tonic-gate  * Check properties to set options. (See dld.h for property definitions).
2290Sstevel@tonic-gate  */
2300Sstevel@tonic-gate static void
2310Sstevel@tonic-gate drv_set_opt(dev_info_t *dip)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2340Sstevel@tonic-gate 	    DLD_PROP_NO_FASTPATH, 0) != 0) {
2350Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_FASTPATH;
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2390Sstevel@tonic-gate 	    DLD_PROP_NO_POLL, 0) != 0) {
2400Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_POLL;
2410Sstevel@tonic-gate 	}
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2440Sstevel@tonic-gate 	    DLD_PROP_NO_ZEROCOPY, 0) != 0) {
2450Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_ZEROCOPY;
2460Sstevel@tonic-gate 	}
2474114Sja97890 
2484114Sja97890 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2494114Sja97890 	    DLD_PROP_NO_SOFTRING, 0) != 0) {
2504114Sja97890 		dld_opt |= DLD_OPT_NO_SOFTRING;
2514114Sja97890 	}
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate /*
2550Sstevel@tonic-gate  * devo_attach: attach(9e)
2560Sstevel@tonic-gate  */
2570Sstevel@tonic-gate static int
2580Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2590Sstevel@tonic-gate {
2600Sstevel@tonic-gate 	if (cmd != DDI_ATTACH)
2610Sstevel@tonic-gate 		return (DDI_FAILURE);
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	ASSERT(ddi_get_instance(dip) == 0);
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate 	drv_set_opt(dip);
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	/*
2680Sstevel@tonic-gate 	 * Create control node. DLPI provider nodes will be created on demand.
2690Sstevel@tonic-gate 	 */
2700Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR,
2710Sstevel@tonic-gate 	    DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS)
2720Sstevel@tonic-gate 		return (DDI_FAILURE);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	dld_dip = dip;
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 	/*
2770Sstevel@tonic-gate 	 * Log the fact that the driver is now attached.
2780Sstevel@tonic-gate 	 */
2790Sstevel@tonic-gate 	ddi_report_dev(dip);
2800Sstevel@tonic-gate 	return (DDI_SUCCESS);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate  * devo_detach: detach(9e)
2850Sstevel@tonic-gate  */
2860Sstevel@tonic-gate static int
2870Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
2900Sstevel@tonic-gate 		return (DDI_FAILURE);
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	ASSERT(dld_dip == dip);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	/*
2950Sstevel@tonic-gate 	 * Remove the control node.
2960Sstevel@tonic-gate 	 */
2970Sstevel@tonic-gate 	ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME);
2980Sstevel@tonic-gate 	dld_dip = NULL;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	return (DDI_SUCCESS);
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate /*
304269Sericheng  * dld control node open procedure.
3050Sstevel@tonic-gate  */
3060Sstevel@tonic-gate /*ARGSUSED*/
3070Sstevel@tonic-gate static int
3080Sstevel@tonic-gate drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
3090Sstevel@tonic-gate {
310269Sericheng 	dld_ctl_str_t	*ctls;
3110Sstevel@tonic-gate 	minor_t		minor;
312269Sericheng 	queue_t *oq =	OTHERQ(rq);
3130Sstevel@tonic-gate 
314269Sericheng 	if (sflag == MODOPEN)
315269Sericheng 		return (ENOTSUP);
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	/*
3180Sstevel@tonic-gate 	 * This is a cloning driver and therefore each queue should only
3190Sstevel@tonic-gate 	 * ever get opened once.
3200Sstevel@tonic-gate 	 */
3210Sstevel@tonic-gate 	if (rq->q_ptr != NULL)
3220Sstevel@tonic-gate 		return (EBUSY);
3230Sstevel@tonic-gate 
324269Sericheng 	minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP);
325269Sericheng 	if (minor == 0)
326269Sericheng 		return (ENOMEM);
3270Sstevel@tonic-gate 
328269Sericheng 	ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP);
329269Sericheng 	if (ctls == NULL) {
330269Sericheng 		vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1);
331269Sericheng 		return (ENOMEM);
332269Sericheng 	}
3330Sstevel@tonic-gate 
334269Sericheng 	ctls->cs_minor = minor;
335269Sericheng 	ctls->cs_wq = WR(rq);
3360Sstevel@tonic-gate 
337269Sericheng 	rq->q_ptr = ctls;
338269Sericheng 	oq->q_ptr = ctls;
3390Sstevel@tonic-gate 
3400Sstevel@tonic-gate 	/*
3410Sstevel@tonic-gate 	 * Enable the queue srv(9e) routine.
3420Sstevel@tonic-gate 	 */
3430Sstevel@tonic-gate 	qprocson(rq);
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	/*
3460Sstevel@tonic-gate 	 * Construct a cloned dev_t to hand back.
3470Sstevel@tonic-gate 	 */
348269Sericheng 	*devp = makedevice(getmajor(*devp), ctls->cs_minor);
3490Sstevel@tonic-gate 	return (0);
3500Sstevel@tonic-gate }
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate /*
353269Sericheng  * dld control node close procedure.
3540Sstevel@tonic-gate  */
3550Sstevel@tonic-gate static int
3560Sstevel@tonic-gate drv_close(queue_t *rq)
3570Sstevel@tonic-gate {
358269Sericheng 	dld_ctl_str_t	*ctls;
3590Sstevel@tonic-gate 
360269Sericheng 	ctls = rq->q_ptr;
361269Sericheng 	ASSERT(ctls != NULL);
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	/*
3640Sstevel@tonic-gate 	 * Disable the queue srv(9e) routine.
3650Sstevel@tonic-gate 	 */
3660Sstevel@tonic-gate 	qprocsoff(rq);
3670Sstevel@tonic-gate 
368269Sericheng 	vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1);
3690Sstevel@tonic-gate 
370269Sericheng 	kmem_free(ctls, sizeof (dld_ctl_str_t));
371269Sericheng 
3720Sstevel@tonic-gate 	return (0);
3730Sstevel@tonic-gate }
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate /*
376269Sericheng  * DLDIOCATTR
3770Sstevel@tonic-gate  */
3780Sstevel@tonic-gate static void
379269Sericheng drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp)
3800Sstevel@tonic-gate {
3812311Sseb 	dld_ioc_attr_t	*diap;
382269Sericheng 	dls_vlan_t	*dvp = NULL;
383269Sericheng 	dls_link_t	*dlp = NULL;
384269Sericheng 	int		err;
385269Sericheng 	queue_t		*q = ctls->cs_wq;
386269Sericheng 
387269Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0)
388269Sericheng 		goto failed;
389269Sericheng 
390269Sericheng 	diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr;
391269Sericheng 	diap->dia_name[IFNAMSIZ - 1] = '\0';
392269Sericheng 
393269Sericheng 	if (dls_vlan_hold(diap->dia_name, &dvp, B_FALSE) != 0) {
394269Sericheng 		err = ENOENT;
395269Sericheng 		goto failed;
396269Sericheng 	}
397269Sericheng 
398269Sericheng 	dlp = dvp->dv_dlp;
3992311Sseb 	(void) strlcpy(diap->dia_dev, dlp->dl_name, sizeof (diap->dia_dev));
400269Sericheng 	diap->dia_vid = dvp->dv_id;
401269Sericheng 	diap->dia_max_sdu = dlp->dl_mip->mi_sdu_max;
402269Sericheng 
403269Sericheng 	dls_vlan_rele(dvp);
404269Sericheng 	miocack(q, mp, sizeof (dld_ioc_attr_t), 0);
405269Sericheng 	return;
406269Sericheng 
407269Sericheng failed:
408269Sericheng 	ASSERT(err != 0);
409269Sericheng 	if (err == ENOENT) {
410269Sericheng 		char	devname[MAXNAMELEN];
411269Sericheng 		uint_t	instance;
412269Sericheng 		major_t	major;
413269Sericheng 
414269Sericheng 		/*
415269Sericheng 		 * Try to detect if the specified device is gldv3
416269Sericheng 		 * and return ENODEV if it is not.
417269Sericheng 		 */
418269Sericheng 		if (ddi_parse(diap->dia_name, devname, &instance) == 0 &&
419269Sericheng 		    (major = ddi_name_to_major(devname)) != (major_t)-1 &&
420269Sericheng 		    !GLDV3_DRV(major))
421269Sericheng 			err = ENODEV;
422269Sericheng 	}
423269Sericheng 	miocnak(q, mp, 0, err);
424269Sericheng }
425269Sericheng 
426269Sericheng 
427269Sericheng /*
428269Sericheng  * DLDIOCVLAN
429269Sericheng  */
430269Sericheng typedef struct dld_ioc_vlan_state {
431269Sericheng 	uint_t		bytes_left;
432733Skrgopi 	dld_ioc_vlan_t	*divp;
433269Sericheng 	dld_vlan_info_t	*vlanp;
434269Sericheng } dld_ioc_vlan_state_t;
435269Sericheng 
436269Sericheng static int
437269Sericheng drv_ioc_vlan_info(dls_vlan_t *dvp, void *arg)
438269Sericheng {
439269Sericheng 	dld_ioc_vlan_state_t	*statep = arg;
4400Sstevel@tonic-gate 
441733Skrgopi 	/*
442733Skrgopi 	 * passed buffer space is limited to 65536 bytes. So
443733Skrgopi 	 * copy only the vlans associated with the passed link.
444733Skrgopi 	 */
4452311Sseb 	if (strcmp(dvp->dv_dlp->dl_name, statep->divp->div_name) == 0 &&
446733Skrgopi 	    dvp->dv_id != 0) {
447733Skrgopi 		if (statep->bytes_left < sizeof (dld_vlan_info_t))
448733Skrgopi 			return (ENOSPC);
449269Sericheng 
450733Skrgopi 		(void) strlcpy(statep->vlanp->dvi_name,
451733Skrgopi 		    dvp->dv_name, IFNAMSIZ);
452733Skrgopi 		statep->divp->div_count++;
453733Skrgopi 		statep->bytes_left -= sizeof (dld_vlan_info_t);
454733Skrgopi 		statep->vlanp += 1;
455733Skrgopi 	}
456269Sericheng 	return (0);
457269Sericheng }
458269Sericheng 
459269Sericheng static void
460269Sericheng drv_ioc_vlan(dld_ctl_str_t *ctls, mblk_t *mp)
461269Sericheng {
462269Sericheng 	dld_ioc_vlan_t		*divp;
463269Sericheng 	dld_ioc_vlan_state_t	state;
464269Sericheng 	int			err = EINVAL;
465269Sericheng 	queue_t			*q = ctls->cs_wq;
466733Skrgopi 	mblk_t			*bp;
467269Sericheng 
468269Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_t))) != 0)
469269Sericheng 		goto failed;
470269Sericheng 
471733Skrgopi 	if ((bp = msgpullup(mp->b_cont, -1)) == NULL)
472733Skrgopi 		goto failed;
473733Skrgopi 
474733Skrgopi 	freemsg(mp->b_cont);
475733Skrgopi 	mp->b_cont = bp;
476733Skrgopi 	divp = (dld_ioc_vlan_t *)bp->b_rptr;
477733Skrgopi 	divp->div_count = 0;
478733Skrgopi 	state.bytes_left = MBLKL(bp) - sizeof (dld_ioc_vlan_t);
479733Skrgopi 	state.divp = divp;
480269Sericheng 	state.vlanp = (dld_vlan_info_t *)(divp + 1);
481269Sericheng 
482269Sericheng 	err = dls_vlan_walk(drv_ioc_vlan_info, &state);
483269Sericheng 	if (err != 0)
484269Sericheng 		goto failed;
4850Sstevel@tonic-gate 
486269Sericheng 	miocack(q, mp, sizeof (dld_ioc_vlan_t) +
487733Skrgopi 	    state.divp->div_count * sizeof (dld_vlan_info_t), 0);
488269Sericheng 	return;
489269Sericheng 
490269Sericheng failed:
491269Sericheng 	ASSERT(err != 0);
492269Sericheng 	miocnak(q, mp, 0, err);
493269Sericheng }
494269Sericheng 
4953448Sdh155122 /*
4963448Sdh155122  * DLDIOCHOLDVLAN
4973448Sdh155122  */
4983448Sdh155122 static void
4993448Sdh155122 drv_hold_vlan(dld_ctl_str_t *ctls, mblk_t *mp)
5003448Sdh155122 {
5013448Sdh155122 	queue_t		*q = ctls->cs_wq;
5023448Sdh155122 	dld_hold_vlan_t	*dhv;
5033448Sdh155122 	mblk_t		*nmp;
5044049Sdh155122 	int		err = EINVAL;
5053448Sdh155122 	dls_vlan_t	*dvp;
5064049Sdh155122 	char		mac[MAXNAMELEN];
5074049Sdh155122 	dev_info_t	*dip = NULL;
5084049Sdh155122 	major_t		major;
5094049Sdh155122 	uint_t		index;
5103448Sdh155122 
5113448Sdh155122 	nmp = mp->b_cont;
5124049Sdh155122 	if (nmp == NULL || MBLKL(nmp) < sizeof (dld_hold_vlan_t))
5134049Sdh155122 		goto failed;
5144049Sdh155122 
5153448Sdh155122 	dhv = (dld_hold_vlan_t *)nmp->b_rptr;
5163448Sdh155122 
5174049Sdh155122 	/*
5184049Sdh155122 	 * When a device instance without opens is detached, its
5194049Sdh155122 	 * dls_vlan_t will be destroyed. A subsequent DLDIOCHOLDVLAN
5204049Sdh155122 	 * invoked on this device instance will fail because
5214049Sdh155122 	 * dls_vlan_hold() does not create non-tagged vlans on demand.
5224049Sdh155122 	 * To handle this problem, we must force the creation of the
5234049Sdh155122 	 * dls_vlan_t (if it doesn't already exist) by calling
5244049Sdh155122 	 * ddi_hold_devi_by_instance() before calling dls_vlan_hold().
5254049Sdh155122 	 */
5264049Sdh155122 	if (ddi_parse(dhv->dhv_name, mac, &index) != DDI_SUCCESS)
5274049Sdh155122 		goto failed;
5284049Sdh155122 
5294049Sdh155122 	if (DLS_PPA2VID(index) == VLAN_ID_NONE && strcmp(mac, "aggr") != 0) {
5304049Sdh155122 		if ((major = ddi_name_to_major(mac)) == (major_t)-1 ||
5314049Sdh155122 		    (dip = ddi_hold_devi_by_instance(major,
5324049Sdh155122 		    DLS_PPA2INST(index), 0)) == NULL)
5334049Sdh155122 			goto failed;
5343448Sdh155122 	}
5353448Sdh155122 
5364049Sdh155122 	err = dls_vlan_hold(dhv->dhv_name, &dvp, B_TRUE);
5374049Sdh155122 	if (dip != NULL)
5384049Sdh155122 		ddi_release_devi(dip);
5394049Sdh155122 
5404049Sdh155122 	if (err != 0)
5414049Sdh155122 		goto failed;
5424049Sdh155122 
5433448Sdh155122 	if ((err = dls_vlan_setzoneid(dhv->dhv_name, dhv->dhv_zid,
5443871Syz147064 	    dhv->dhv_docheck)) != 0) {
5453871Syz147064 		dls_vlan_rele(dvp);
5464049Sdh155122 		goto failed;
5473871Syz147064 	} else {
5483448Sdh155122 		miocack(q, mp, 0, 0);
5494049Sdh155122 		return;
5503871Syz147064 	}
5514049Sdh155122 failed:
5524049Sdh155122 	miocnak(q, mp, 0, err);
5533448Sdh155122 }
5543448Sdh155122 
5553448Sdh155122 /*
5563448Sdh155122  * DLDIOCRELEVLAN
5573448Sdh155122  */
5583448Sdh155122 static void
5593448Sdh155122 drv_rele_vlan(dld_ctl_str_t *ctls, mblk_t *mp)
5603448Sdh155122 {
5613448Sdh155122 	queue_t		*q = ctls->cs_wq;
5623448Sdh155122 	dld_hold_vlan_t	*dhv;
5633448Sdh155122 	mblk_t		*nmp;
5643448Sdh155122 	int		err;
5653448Sdh155122 
5663448Sdh155122 	nmp = mp->b_cont;
5673448Sdh155122 	if (nmp == NULL || MBLKL(nmp) < sizeof (dld_hold_vlan_t)) {
5683448Sdh155122 		err = EINVAL;
5693448Sdh155122 		miocnak(q, mp, 0, err);
5703448Sdh155122 		return;
5713448Sdh155122 	}
5723448Sdh155122 	dhv = (dld_hold_vlan_t *)nmp->b_rptr;
5733448Sdh155122 
5743448Sdh155122 	if ((err = dls_vlan_setzoneid(dhv->dhv_name, dhv->dhv_zid,
5753448Sdh155122 	    dhv->dhv_docheck)) != 0) {
5763448Sdh155122 		miocnak(q, mp, 0, err);
5773448Sdh155122 		return;
5783448Sdh155122 	}
5793448Sdh155122 
5803448Sdh155122 	if ((err = dls_vlan_rele_by_name(dhv->dhv_name)) != 0) {
5813448Sdh155122 		miocnak(q, mp, 0, err);
5823448Sdh155122 		return;
5833448Sdh155122 	}
5843448Sdh155122 
5853448Sdh155122 	miocack(q, mp, 0, 0);
5863448Sdh155122 }
5873448Sdh155122 
5883448Sdh155122 /*
5893448Sdh155122  * DLDIOCZIDGET
5903448Sdh155122  */
5913448Sdh155122 static void
5923448Sdh155122 drv_ioc_zid_get(dld_ctl_str_t *ctls, mblk_t *mp)
5933448Sdh155122 {
5943448Sdh155122 	queue_t		*q = ctls->cs_wq;
5953448Sdh155122 	dld_hold_vlan_t	*dhv;
5963448Sdh155122 	mblk_t		*nmp;
5973448Sdh155122 	int		err;
5983448Sdh155122 
5993448Sdh155122 	nmp = mp->b_cont;
6003448Sdh155122 	if (nmp == NULL || MBLKL(nmp) < sizeof (dld_hold_vlan_t)) {
6013448Sdh155122 		err = EINVAL;
6023448Sdh155122 		miocnak(q, mp, 0, err);
6033448Sdh155122 		return;
6043448Sdh155122 	}
6053448Sdh155122 	dhv = (dld_hold_vlan_t *)nmp->b_rptr;
6063448Sdh155122 
6073448Sdh155122 	if ((err = dls_vlan_getzoneid(dhv->dhv_name, &dhv->dhv_zid)) != 0)
6083448Sdh155122 		miocnak(q, mp, 0, err);
6093448Sdh155122 	else
6103448Sdh155122 		miocack(q, mp, sizeof (dld_hold_vlan_t), 0);
6113448Sdh155122 }
612269Sericheng 
613269Sericheng /*
614269Sericheng  * Process an IOCTL message received by the control node.
615269Sericheng  */
616269Sericheng static void
617269Sericheng drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp)
618269Sericheng {
619269Sericheng 	uint_t	cmd;
620269Sericheng 
621269Sericheng 	cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
622269Sericheng 	switch (cmd) {
623269Sericheng 	case DLDIOCATTR:
624269Sericheng 		drv_ioc_attr(ctls, mp);
625269Sericheng 		return;
626269Sericheng 	case DLDIOCVLAN:
627269Sericheng 		drv_ioc_vlan(ctls, mp);
628269Sericheng 		return;
6293147Sxc151355 	case DLDIOCSECOBJSET:
6303147Sxc151355 		drv_ioc_secobj_set(ctls, mp);
6313147Sxc151355 		return;
6323147Sxc151355 	case DLDIOCSECOBJGET:
6333147Sxc151355 		drv_ioc_secobj_get(ctls, mp);
6343147Sxc151355 		return;
6353147Sxc151355 	case DLDIOCSECOBJUNSET:
6363147Sxc151355 		drv_ioc_secobj_unset(ctls, mp);
6373147Sxc151355 		return;
6383448Sdh155122 	case DLDIOCHOLDVLAN:
6393448Sdh155122 		drv_hold_vlan(ctls, mp);
6403448Sdh155122 		return;
6413448Sdh155122 	case DLDIOCRELEVLAN:
6423448Sdh155122 		drv_rele_vlan(ctls, mp);
6433448Sdh155122 		return;
6443448Sdh155122 	case DLDIOCZIDGET:
6453448Sdh155122 		drv_ioc_zid_get(ctls, mp);
6463448Sdh155122 		return;
647269Sericheng 	default:
648269Sericheng 		miocnak(ctls->cs_wq, mp, 0, ENOTSUP);
649269Sericheng 		return;
650269Sericheng 	}
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate /*
654269Sericheng  * Write side put routine of the dld control node.
6550Sstevel@tonic-gate  */
6560Sstevel@tonic-gate static void
657269Sericheng drv_uw_put(queue_t *q, mblk_t *mp)
6580Sstevel@tonic-gate {
659269Sericheng 	dld_ctl_str_t *ctls = q->q_ptr;
6600Sstevel@tonic-gate 
661269Sericheng 	switch (mp->b_datap->db_type) {
662269Sericheng 	case M_IOCTL:
663269Sericheng 		drv_ioc(ctls, mp);
664269Sericheng 		break;
665269Sericheng 	default:
666269Sericheng 		freemsg(mp);
667269Sericheng 		break;
668269Sericheng 	}
669269Sericheng }
6700Sstevel@tonic-gate 
671269Sericheng /*
672269Sericheng  * Write-side service procedure.
673269Sericheng  */
674269Sericheng void
675269Sericheng drv_uw_srv(queue_t *q)
676269Sericheng {
677269Sericheng 	mblk_t *mp;
6780Sstevel@tonic-gate 
679269Sericheng 	while (mp = getq(q))
680269Sericheng 		drv_uw_put(q, mp);
6810Sstevel@tonic-gate }
6823147Sxc151355 
6833147Sxc151355 /*
6843147Sxc151355  * Secure objects implementation
6853147Sxc151355  */
6863147Sxc151355 
6873147Sxc151355 /* ARGSUSED */
6883147Sxc151355 static int
6893147Sxc151355 drv_secobj_ctor(void *buf, void *arg, int kmflag)
6903147Sxc151355 {
6913147Sxc151355 	bzero(buf, sizeof (dld_secobj_t));
6923147Sxc151355 	return (0);
6933147Sxc151355 }
6943147Sxc151355 
6953147Sxc151355 static void
6963147Sxc151355 drv_secobj_init(void)
6973147Sxc151355 {
6983147Sxc151355 	rw_init(&drv_secobj_lock, NULL, RW_DEFAULT, NULL);
6993147Sxc151355 	drv_secobj_cachep = kmem_cache_create("drv_secobj_cache",
7003147Sxc151355 	    sizeof (dld_secobj_t), 0, drv_secobj_ctor, NULL,
7013147Sxc151355 	    NULL, NULL, NULL, 0);
7023147Sxc151355 	drv_secobj_hash = mod_hash_create_extended("drv_secobj_hash",
7033147Sxc151355 	    SECOBJ_WEP_HASHSZ, mod_hash_null_keydtor, mod_hash_null_valdtor,
7043147Sxc151355 	    mod_hash_bystr, NULL, mod_hash_strkey_cmp, KM_SLEEP);
7053147Sxc151355 }
7063147Sxc151355 
7073147Sxc151355 static void
7083147Sxc151355 drv_secobj_fini(void)
7093147Sxc151355 {
7103147Sxc151355 	mod_hash_destroy_hash(drv_secobj_hash);
7113147Sxc151355 	kmem_cache_destroy(drv_secobj_cachep);
7123147Sxc151355 	rw_destroy(&drv_secobj_lock);
7133147Sxc151355 }
7143147Sxc151355 
7153147Sxc151355 static void
7163147Sxc151355 drv_ioc_secobj_set(dld_ctl_str_t *ctls, mblk_t *mp)
7173147Sxc151355 {
7183147Sxc151355 	dld_ioc_secobj_set_t	*ssp;
7193147Sxc151355 	dld_secobj_t		*sobjp, *objp;
7203147Sxc151355 	int			err = EINVAL;
7213147Sxc151355 	queue_t			*q = ctls->cs_wq;
7223147Sxc151355 
7233147Sxc151355 	if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_set_t))) != 0)
7243147Sxc151355 		goto failed;
7253147Sxc151355 
7263147Sxc151355 	ssp = (dld_ioc_secobj_set_t *)mp->b_cont->b_rptr;
7273147Sxc151355 	sobjp = &ssp->ss_obj;
7283147Sxc151355 
729*4126Szf162725 	if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP &&
730*4126Szf162725 	    sobjp->so_class != DLD_SECOBJ_CLASS_WPA)
7313147Sxc151355 		goto failed;
7323147Sxc151355 
7333147Sxc151355 	if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' ||
7343147Sxc151355 	    sobjp->so_len > DLD_SECOBJ_VAL_MAX)
7353147Sxc151355 		goto failed;
7363147Sxc151355 
7373147Sxc151355 	rw_enter(&drv_secobj_lock, RW_WRITER);
7383147Sxc151355 	err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sobjp->so_name,
7393147Sxc151355 	    (mod_hash_val_t *)&objp);
7403147Sxc151355 	if (err == 0) {
7413147Sxc151355 		if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) != 0) {
7423147Sxc151355 			err = EEXIST;
7433147Sxc151355 			rw_exit(&drv_secobj_lock);
7443147Sxc151355 			goto failed;
7453147Sxc151355 		}
7463147Sxc151355 	} else {
7473147Sxc151355 		ASSERT(err == MH_ERR_NOTFOUND);
7483147Sxc151355 		if ((ssp->ss_flags & DLD_SECOBJ_OPT_CREATE) == 0) {
7493147Sxc151355 			err = ENOENT;
7503147Sxc151355 			rw_exit(&drv_secobj_lock);
7513147Sxc151355 			goto failed;
7523147Sxc151355 		}
7533147Sxc151355 		objp = kmem_cache_alloc(drv_secobj_cachep, KM_SLEEP);
7543147Sxc151355 		(void) strlcpy(objp->so_name, sobjp->so_name,
7553147Sxc151355 		    DLD_SECOBJ_NAME_MAX);
7563147Sxc151355 
7573147Sxc151355 		err = mod_hash_insert(drv_secobj_hash,
7583147Sxc151355 		    (mod_hash_key_t)objp->so_name, (mod_hash_val_t)objp);
7593147Sxc151355 		ASSERT(err == 0);
7603147Sxc151355 	}
7613147Sxc151355 	bcopy(sobjp->so_val, objp->so_val, sobjp->so_len);
7623147Sxc151355 	objp->so_len = sobjp->so_len;
7633147Sxc151355 	objp->so_class = sobjp->so_class;
7643147Sxc151355 	rw_exit(&drv_secobj_lock);
7653147Sxc151355 	miocack(q, mp, 0, 0);
7663147Sxc151355 	return;
7673147Sxc151355 
7683147Sxc151355 failed:
7693147Sxc151355 	ASSERT(err != 0);
7703147Sxc151355 	miocnak(q, mp, 0, err);
7713147Sxc151355 }
7723147Sxc151355 
7733147Sxc151355 typedef struct dld_secobj_state {
7743147Sxc151355 	uint_t		ss_free;
7753147Sxc151355 	uint_t		ss_count;
7763147Sxc151355 	int		ss_rc;
7773147Sxc151355 	dld_secobj_t	*ss_objp;
7783147Sxc151355 } dld_secobj_state_t;
7793147Sxc151355 
7803147Sxc151355 /* ARGSUSED */
7813147Sxc151355 static uint_t
7823147Sxc151355 drv_secobj_walker(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
7833147Sxc151355 {
7843147Sxc151355 	dld_secobj_state_t	*statep = arg;
7853147Sxc151355 	dld_secobj_t		*sobjp = (dld_secobj_t *)val;
7863147Sxc151355 
7873147Sxc151355 	if (statep->ss_free < sizeof (dld_secobj_t)) {
7883147Sxc151355 		statep->ss_rc = ENOSPC;
7893147Sxc151355 		return (MH_WALK_TERMINATE);
7903147Sxc151355 	}
7913147Sxc151355 	bcopy(sobjp, statep->ss_objp, sizeof (dld_secobj_t));
7923147Sxc151355 	statep->ss_objp++;
7933147Sxc151355 	statep->ss_free -= sizeof (dld_secobj_t);
7943147Sxc151355 	statep->ss_count++;
7953147Sxc151355 	return (MH_WALK_CONTINUE);
7963147Sxc151355 }
7973147Sxc151355 
7983147Sxc151355 static void
7993147Sxc151355 drv_ioc_secobj_get(dld_ctl_str_t *ctls, mblk_t *mp)
8003147Sxc151355 {
8013147Sxc151355 	dld_ioc_secobj_get_t	*sgp;
8023147Sxc151355 	dld_secobj_t		*sobjp, *objp;
8033147Sxc151355 	int			err = EINVAL;
8043147Sxc151355 	uint_t			extra = 0;
8053147Sxc151355 	queue_t			*q = ctls->cs_wq;
8063147Sxc151355 	mblk_t			*bp;
8073147Sxc151355 
8083147Sxc151355 	if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_get_t))) != 0)
8093147Sxc151355 		goto failed;
8103147Sxc151355 
8113147Sxc151355 	if ((bp = msgpullup(mp->b_cont, -1)) == NULL)
8123147Sxc151355 		goto failed;
8133147Sxc151355 
8143147Sxc151355 	freemsg(mp->b_cont);
8153147Sxc151355 	mp->b_cont = bp;
8163147Sxc151355 	sgp = (dld_ioc_secobj_get_t *)bp->b_rptr;
8173147Sxc151355 	sobjp = &sgp->sg_obj;
8183147Sxc151355 
8193147Sxc151355 	if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0')
8203147Sxc151355 		goto failed;
8213147Sxc151355 
8223147Sxc151355 	rw_enter(&drv_secobj_lock, RW_READER);
8233147Sxc151355 	if (sobjp->so_name[0] != '\0') {
8243147Sxc151355 		err = mod_hash_find(drv_secobj_hash,
8253147Sxc151355 		    (mod_hash_key_t)sobjp->so_name, (mod_hash_val_t *)&objp);
8263147Sxc151355 		if (err != 0) {
8273147Sxc151355 			ASSERT(err == MH_ERR_NOTFOUND);
8283147Sxc151355 			err = ENOENT;
8293147Sxc151355 			rw_exit(&drv_secobj_lock);
8303147Sxc151355 			goto failed;
8313147Sxc151355 		}
8323147Sxc151355 		bcopy(objp->so_val, sobjp->so_val, objp->so_len);
8333147Sxc151355 		sobjp->so_len = objp->so_len;
8343147Sxc151355 		sobjp->so_class = objp->so_class;
8353147Sxc151355 		sgp->sg_count = 1;
8363147Sxc151355 	} else {
8373147Sxc151355 		dld_secobj_state_t	state;
8383147Sxc151355 
8393147Sxc151355 		state.ss_free = MBLKL(bp) - sizeof (dld_ioc_secobj_get_t);
8403147Sxc151355 		state.ss_count = 0;
8413147Sxc151355 		state.ss_rc = 0;
8423147Sxc151355 		state.ss_objp = (dld_secobj_t *)(sgp + 1);
8433147Sxc151355 		mod_hash_walk(drv_secobj_hash, drv_secobj_walker, &state);
8443147Sxc151355 		if (state.ss_rc != 0) {
8453147Sxc151355 			err = state.ss_rc;
8463147Sxc151355 			rw_exit(&drv_secobj_lock);
8473147Sxc151355 			goto failed;
8483147Sxc151355 		}
8493147Sxc151355 		sgp->sg_count = state.ss_count;
8503147Sxc151355 		extra = state.ss_count * sizeof (dld_secobj_t);
8513147Sxc151355 	}
8523147Sxc151355 	rw_exit(&drv_secobj_lock);
8533147Sxc151355 	miocack(q, mp, sizeof (dld_ioc_secobj_get_t) + extra, 0);
8543147Sxc151355 	return;
8553147Sxc151355 
8563147Sxc151355 failed:
8573147Sxc151355 	ASSERT(err != 0);
8583147Sxc151355 	miocnak(q, mp, 0, err);
8593147Sxc151355 
8603147Sxc151355 }
8613147Sxc151355 
8623147Sxc151355 static void
8633147Sxc151355 drv_ioc_secobj_unset(dld_ctl_str_t *ctls, mblk_t *mp)
8643147Sxc151355 {
8653147Sxc151355 	dld_ioc_secobj_unset_t	*sup;
8663147Sxc151355 	dld_secobj_t		*objp;
8673147Sxc151355 	mod_hash_val_t		val;
8683147Sxc151355 	int			err = EINVAL;
8693147Sxc151355 	queue_t			*q = ctls->cs_wq;
8703147Sxc151355 
8713147Sxc151355 	if ((err = miocpullup(mp, sizeof (dld_ioc_secobj_unset_t))) != 0)
8723147Sxc151355 		goto failed;
8733147Sxc151355 
8743147Sxc151355 	sup = (dld_ioc_secobj_unset_t *)mp->b_cont->b_rptr;
8753147Sxc151355 	if (sup->su_name[DLD_SECOBJ_NAME_MAX - 1] != '\0')
8763147Sxc151355 		goto failed;
8773147Sxc151355 
8783147Sxc151355 	rw_enter(&drv_secobj_lock, RW_WRITER);
8793147Sxc151355 	err = mod_hash_find(drv_secobj_hash, (mod_hash_key_t)sup->su_name,
8803147Sxc151355 	    (mod_hash_val_t *)&objp);
8813147Sxc151355 	if (err != 0) {
8823147Sxc151355 		ASSERT(err == MH_ERR_NOTFOUND);
8833147Sxc151355 		err = ENOENT;
8843147Sxc151355 		rw_exit(&drv_secobj_lock);
8853147Sxc151355 		goto failed;
8863147Sxc151355 	}
8873147Sxc151355 	err = mod_hash_remove(drv_secobj_hash, (mod_hash_key_t)sup->su_name,
8883147Sxc151355 	    (mod_hash_val_t *)&val);
8893147Sxc151355 	ASSERT(err == 0);
8903147Sxc151355 	ASSERT(objp == (dld_secobj_t *)val);
8913147Sxc151355 
8923147Sxc151355 	kmem_cache_free(drv_secobj_cachep, objp);
8933147Sxc151355 	rw_exit(&drv_secobj_lock);
8943147Sxc151355 	miocack(q, mp, 0, 0);
8953147Sxc151355 	return;
8963147Sxc151355 
8973147Sxc151355 failed:
8983147Sxc151355 	ASSERT(err != 0);
8993147Sxc151355 	miocnak(q, mp, 0, err);
9003147Sxc151355 }
901