xref: /onnv-gate/usr/src/uts/common/io/dld/dld_drv.c (revision 2311:2d86e52dcdf0)
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
5*2311Sseb  * Common Development and Distribution License (the "License").
6*2311Sseb  * 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 /*
22*2311Sseb  * Copyright 2006 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>
400Sstevel@tonic-gate #include	<inet/common.h>
410Sstevel@tonic-gate 
42269Sericheng /*
43269Sericheng  * dld control node state, one per open control node session.
44269Sericheng  */
45269Sericheng typedef struct dld_ctl_str_s {
46269Sericheng 	minor_t cs_minor;
47269Sericheng 	queue_t *cs_wq;
48269Sericheng } dld_ctl_str_t;
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static void	drv_init(void);
510Sstevel@tonic-gate static int	drv_fini(void);
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static int	drv_getinfo(dev_info_t	*, ddi_info_cmd_t, void *, void **);
540Sstevel@tonic-gate static int	drv_attach(dev_info_t *, ddi_attach_cmd_t);
550Sstevel@tonic-gate static int	drv_detach(dev_info_t *, ddi_detach_cmd_t);
560Sstevel@tonic-gate 
57269Sericheng /*
58269Sericheng  * The following entry points are private to dld and are used for control
59269Sericheng  * operations only. The entry points exported to mac drivers are defined
60269Sericheng  * in dld_str.c. Refer to the comment on top of dld_str.c for details.
61269Sericheng  */
620Sstevel@tonic-gate static int	drv_open(queue_t *, dev_t *, int, int, cred_t *);
630Sstevel@tonic-gate static int	drv_close(queue_t *);
640Sstevel@tonic-gate 
650Sstevel@tonic-gate static void	drv_uw_put(queue_t *, mblk_t *);
660Sstevel@tonic-gate static void	drv_uw_srv(queue_t *);
670Sstevel@tonic-gate 
680Sstevel@tonic-gate dev_info_t	*dld_dip;		/* dev_info_t for the driver */
69269Sericheng uint32_t	dld_opt = 0;		/* Global options */
70269Sericheng static vmem_t	*dld_ctl_vmem;		/* for control minor numbers */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static	struct	module_info	drv_info = {
730Sstevel@tonic-gate 	0,			/* mi_idnum */
740Sstevel@tonic-gate 	DLD_DRIVER_NAME,	/* mi_idname */
750Sstevel@tonic-gate 	0,			/* mi_minpsz */
760Sstevel@tonic-gate 	(64 * 1024),		/* mi_maxpsz */
770Sstevel@tonic-gate 	1,			/* mi_hiwat */
780Sstevel@tonic-gate 	0			/* mi_lowat */
790Sstevel@tonic-gate };
800Sstevel@tonic-gate 
810Sstevel@tonic-gate static	struct qinit		drv_ur_init = {
820Sstevel@tonic-gate 	NULL,			/* qi_putp */
830Sstevel@tonic-gate 	NULL,			/* qi_srvp */
840Sstevel@tonic-gate 	drv_open,		/* qi_qopen */
850Sstevel@tonic-gate 	drv_close,		/* qi_qclose */
860Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
870Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
880Sstevel@tonic-gate 	NULL			/* qi_mstat */
890Sstevel@tonic-gate };
900Sstevel@tonic-gate 
910Sstevel@tonic-gate static	struct qinit		drv_uw_init = {
920Sstevel@tonic-gate 	(pfi_t)drv_uw_put,	/* qi_putp */
930Sstevel@tonic-gate 	(pfi_t)drv_uw_srv,	/* qi_srvp */
940Sstevel@tonic-gate 	NULL,			/* qi_qopen */
950Sstevel@tonic-gate 	NULL,			/* qi_qclose */
960Sstevel@tonic-gate 	NULL,			/* qi_qadmin */
970Sstevel@tonic-gate 	&drv_info,		/* qi_minfo */
980Sstevel@tonic-gate 	NULL			/* qi_mstat */
990Sstevel@tonic-gate };
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate static	struct streamtab	drv_stream = {
1020Sstevel@tonic-gate 	&drv_ur_init,		/* st_rdinit */
1030Sstevel@tonic-gate 	&drv_uw_init,		/* st_wrinit */
1040Sstevel@tonic-gate 	NULL,			/* st_muxrinit */
1050Sstevel@tonic-gate 	NULL			/* st_muxwinit */
1060Sstevel@tonic-gate };
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate DDI_DEFINE_STREAM_OPS(drv_ops, nulldev, nulldev, drv_attach, drv_detach,
109269Sericheng     nodev, drv_getinfo, D_MP, &drv_stream);
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /*
1120Sstevel@tonic-gate  * Module linkage information for the kernel.
1130Sstevel@tonic-gate  */
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate extern	struct mod_ops		mod_driverops;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate static	struct modldrv		drv_modldrv = {
1180Sstevel@tonic-gate 	&mod_driverops,
1190Sstevel@tonic-gate 	DLD_INFO,
1200Sstevel@tonic-gate 	&drv_ops
1210Sstevel@tonic-gate };
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate static	struct modlinkage	drv_modlinkage = {
1240Sstevel@tonic-gate 	MODREV_1,
1250Sstevel@tonic-gate 	&drv_modldrv,
1260Sstevel@tonic-gate 	NULL
1270Sstevel@tonic-gate };
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate int
1300Sstevel@tonic-gate _init(void)
1310Sstevel@tonic-gate {
1320Sstevel@tonic-gate 	int	err;
1330Sstevel@tonic-gate 
134269Sericheng 	drv_init();
135269Sericheng 
1360Sstevel@tonic-gate 	if ((err = mod_install(&drv_modlinkage)) != 0)
1370Sstevel@tonic-gate 		return (err);
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	return (0);
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate int
1430Sstevel@tonic-gate _fini(void)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate 	int	err;
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	if ((err = mod_remove(&drv_modlinkage)) != 0)
1480Sstevel@tonic-gate 		return (err);
1490Sstevel@tonic-gate 
150269Sericheng 	if (drv_fini() != 0) {
151269Sericheng 		(void) mod_install(&drv_modlinkage);
152269Sericheng 		return (DDI_FAILURE);
153269Sericheng 	}
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	return (err);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate int
1590Sstevel@tonic-gate _info(struct modinfo *modinfop)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate 	return (mod_info(&drv_modlinkage, modinfop));
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate /*
166269Sericheng  * Initialize component modules.
1670Sstevel@tonic-gate  */
1680Sstevel@tonic-gate static void
1690Sstevel@tonic-gate drv_init(void)
1700Sstevel@tonic-gate {
171269Sericheng 	dld_ctl_vmem = vmem_create("dld_ctl", (void *)1, MAXMIN, 1,
172269Sericheng 	    NULL, NULL, NULL, 1, VM_SLEEP | VMC_IDENTIFIER);
1730Sstevel@tonic-gate 	dld_str_init();
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate static int
1770Sstevel@tonic-gate drv_fini(void)
1780Sstevel@tonic-gate {
1790Sstevel@tonic-gate 	int	err;
1800Sstevel@tonic-gate 
181269Sericheng 	if ((err = dld_str_fini()) != 0)
1820Sstevel@tonic-gate 		return (err);
1830Sstevel@tonic-gate 
184269Sericheng 	vmem_destroy(dld_ctl_vmem);
1850Sstevel@tonic-gate 	return (0);
1860Sstevel@tonic-gate }
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate /*
1890Sstevel@tonic-gate  * devo_getinfo: getinfo(9e)
1900Sstevel@tonic-gate  */
1910Sstevel@tonic-gate /*ARGSUSED*/
1920Sstevel@tonic-gate static int
1930Sstevel@tonic-gate drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resp)
1940Sstevel@tonic-gate {
1950Sstevel@tonic-gate 	if (dld_dip == NULL)
1960Sstevel@tonic-gate 		return (DDI_FAILURE);
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	switch (cmd) {
1990Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
2000Sstevel@tonic-gate 		*resp = (void *)0;
2010Sstevel@tonic-gate 		break;
2020Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
2030Sstevel@tonic-gate 		*resp = (void *)dld_dip;
2040Sstevel@tonic-gate 		break;
2050Sstevel@tonic-gate 	default:
2060Sstevel@tonic-gate 		return (DDI_FAILURE);
2070Sstevel@tonic-gate 	}
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate 	return (DDI_SUCCESS);
2100Sstevel@tonic-gate }
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate /*
2130Sstevel@tonic-gate  * Check properties to set options. (See dld.h for property definitions).
2140Sstevel@tonic-gate  */
2150Sstevel@tonic-gate static void
2160Sstevel@tonic-gate drv_set_opt(dev_info_t *dip)
2170Sstevel@tonic-gate {
2180Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2190Sstevel@tonic-gate 	    DLD_PROP_NO_FASTPATH, 0) != 0) {
2200Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_FASTPATH;
2210Sstevel@tonic-gate 	}
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2240Sstevel@tonic-gate 	    DLD_PROP_NO_POLL, 0) != 0) {
2250Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_POLL;
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	if (ddi_prop_get_int(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
2290Sstevel@tonic-gate 	    DLD_PROP_NO_ZEROCOPY, 0) != 0) {
2300Sstevel@tonic-gate 		dld_opt |= DLD_OPT_NO_ZEROCOPY;
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate }
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate  * devo_attach: attach(9e)
2360Sstevel@tonic-gate  */
2370Sstevel@tonic-gate static int
2380Sstevel@tonic-gate drv_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate 	if (cmd != DDI_ATTACH)
2410Sstevel@tonic-gate 		return (DDI_FAILURE);
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	ASSERT(ddi_get_instance(dip) == 0);
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	drv_set_opt(dip);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	/*
2480Sstevel@tonic-gate 	 * Create control node. DLPI provider nodes will be created on demand.
2490Sstevel@tonic-gate 	 */
2500Sstevel@tonic-gate 	if (ddi_create_minor_node(dip, DLD_CONTROL_MINOR_NAME, S_IFCHR,
2510Sstevel@tonic-gate 	    DLD_CONTROL_MINOR, DDI_PSEUDO, 0) != DDI_SUCCESS)
2520Sstevel@tonic-gate 		return (DDI_FAILURE);
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 	dld_dip = dip;
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	/*
2570Sstevel@tonic-gate 	 * Log the fact that the driver is now attached.
2580Sstevel@tonic-gate 	 */
2590Sstevel@tonic-gate 	ddi_report_dev(dip);
2600Sstevel@tonic-gate 	return (DDI_SUCCESS);
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate /*
2640Sstevel@tonic-gate  * devo_detach: detach(9e)
2650Sstevel@tonic-gate  */
2660Sstevel@tonic-gate static int
2670Sstevel@tonic-gate drv_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate 	if (cmd != DDI_DETACH)
2700Sstevel@tonic-gate 		return (DDI_FAILURE);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	ASSERT(dld_dip == dip);
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	/*
2750Sstevel@tonic-gate 	 * Remove the control node.
2760Sstevel@tonic-gate 	 */
2770Sstevel@tonic-gate 	ddi_remove_minor_node(dip, DLD_CONTROL_MINOR_NAME);
2780Sstevel@tonic-gate 	dld_dip = NULL;
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	return (DDI_SUCCESS);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate /*
284269Sericheng  * dld control node open procedure.
2850Sstevel@tonic-gate  */
2860Sstevel@tonic-gate /*ARGSUSED*/
2870Sstevel@tonic-gate static int
2880Sstevel@tonic-gate drv_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
2890Sstevel@tonic-gate {
290269Sericheng 	dld_ctl_str_t	*ctls;
2910Sstevel@tonic-gate 	minor_t		minor;
292269Sericheng 	queue_t *oq =	OTHERQ(rq);
2930Sstevel@tonic-gate 
294269Sericheng 	if (sflag == MODOPEN)
295269Sericheng 		return (ENOTSUP);
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 	/*
2980Sstevel@tonic-gate 	 * This is a cloning driver and therefore each queue should only
2990Sstevel@tonic-gate 	 * ever get opened once.
3000Sstevel@tonic-gate 	 */
3010Sstevel@tonic-gate 	if (rq->q_ptr != NULL)
3020Sstevel@tonic-gate 		return (EBUSY);
3030Sstevel@tonic-gate 
304269Sericheng 	minor = (minor_t)(uintptr_t)vmem_alloc(dld_ctl_vmem, 1, VM_NOSLEEP);
305269Sericheng 	if (minor == 0)
306269Sericheng 		return (ENOMEM);
3070Sstevel@tonic-gate 
308269Sericheng 	ctls = kmem_zalloc(sizeof (dld_ctl_str_t), KM_NOSLEEP);
309269Sericheng 	if (ctls == NULL) {
310269Sericheng 		vmem_free(dld_ctl_vmem, (void *)(uintptr_t)minor, 1);
311269Sericheng 		return (ENOMEM);
312269Sericheng 	}
3130Sstevel@tonic-gate 
314269Sericheng 	ctls->cs_minor = minor;
315269Sericheng 	ctls->cs_wq = WR(rq);
3160Sstevel@tonic-gate 
317269Sericheng 	rq->q_ptr = ctls;
318269Sericheng 	oq->q_ptr = ctls;
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	/*
3210Sstevel@tonic-gate 	 * Enable the queue srv(9e) routine.
3220Sstevel@tonic-gate 	 */
3230Sstevel@tonic-gate 	qprocson(rq);
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	/*
3260Sstevel@tonic-gate 	 * Construct a cloned dev_t to hand back.
3270Sstevel@tonic-gate 	 */
328269Sericheng 	*devp = makedevice(getmajor(*devp), ctls->cs_minor);
3290Sstevel@tonic-gate 	return (0);
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate /*
333269Sericheng  * dld control node close procedure.
3340Sstevel@tonic-gate  */
3350Sstevel@tonic-gate static int
3360Sstevel@tonic-gate drv_close(queue_t *rq)
3370Sstevel@tonic-gate {
338269Sericheng 	dld_ctl_str_t	*ctls;
3390Sstevel@tonic-gate 
340269Sericheng 	ctls = rq->q_ptr;
341269Sericheng 	ASSERT(ctls != NULL);
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	/*
3440Sstevel@tonic-gate 	 * Disable the queue srv(9e) routine.
3450Sstevel@tonic-gate 	 */
3460Sstevel@tonic-gate 	qprocsoff(rq);
3470Sstevel@tonic-gate 
348269Sericheng 	vmem_free(dld_ctl_vmem, (void *)(uintptr_t)ctls->cs_minor, 1);
3490Sstevel@tonic-gate 
350269Sericheng 	kmem_free(ctls, sizeof (dld_ctl_str_t));
351269Sericheng 
3520Sstevel@tonic-gate 	return (0);
3530Sstevel@tonic-gate }
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate /*
356269Sericheng  * DLDIOCATTR
3570Sstevel@tonic-gate  */
3580Sstevel@tonic-gate static void
359269Sericheng drv_ioc_attr(dld_ctl_str_t *ctls, mblk_t *mp)
3600Sstevel@tonic-gate {
361*2311Sseb 	dld_ioc_attr_t	*diap;
362269Sericheng 	dls_vlan_t	*dvp = NULL;
363269Sericheng 	dls_link_t	*dlp = NULL;
364269Sericheng 	int		err;
365269Sericheng 	queue_t		*q = ctls->cs_wq;
366269Sericheng 
367269Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_attr_t))) != 0)
368269Sericheng 		goto failed;
369269Sericheng 
370269Sericheng 	diap = (dld_ioc_attr_t *)mp->b_cont->b_rptr;
371269Sericheng 	diap->dia_name[IFNAMSIZ - 1] = '\0';
372269Sericheng 
373269Sericheng 	if (dls_vlan_hold(diap->dia_name, &dvp, B_FALSE) != 0) {
374269Sericheng 		err = ENOENT;
375269Sericheng 		goto failed;
376269Sericheng 	}
377269Sericheng 
378269Sericheng 	dlp = dvp->dv_dlp;
379*2311Sseb 	(void) strlcpy(diap->dia_dev, dlp->dl_name, sizeof (diap->dia_dev));
380269Sericheng 	diap->dia_vid = dvp->dv_id;
381269Sericheng 	diap->dia_max_sdu = dlp->dl_mip->mi_sdu_max;
382269Sericheng 
383269Sericheng 	dls_vlan_rele(dvp);
384269Sericheng 	miocack(q, mp, sizeof (dld_ioc_attr_t), 0);
385269Sericheng 	return;
386269Sericheng 
387269Sericheng failed:
388269Sericheng 	ASSERT(err != 0);
389269Sericheng 	if (err == ENOENT) {
390269Sericheng 		char	devname[MAXNAMELEN];
391269Sericheng 		uint_t	instance;
392269Sericheng 		major_t	major;
393269Sericheng 
394269Sericheng 		/*
395269Sericheng 		 * Try to detect if the specified device is gldv3
396269Sericheng 		 * and return ENODEV if it is not.
397269Sericheng 		 */
398269Sericheng 		if (ddi_parse(diap->dia_name, devname, &instance) == 0 &&
399269Sericheng 		    (major = ddi_name_to_major(devname)) != (major_t)-1 &&
400269Sericheng 		    !GLDV3_DRV(major))
401269Sericheng 			err = ENODEV;
402269Sericheng 	}
403269Sericheng 	miocnak(q, mp, 0, err);
404269Sericheng }
405269Sericheng 
406269Sericheng 
407269Sericheng /*
408269Sericheng  * DLDIOCVLAN
409269Sericheng  */
410269Sericheng typedef struct dld_ioc_vlan_state {
411269Sericheng 	uint_t		bytes_left;
412733Skrgopi 	dld_ioc_vlan_t	*divp;
413269Sericheng 	dld_vlan_info_t	*vlanp;
414269Sericheng } dld_ioc_vlan_state_t;
415269Sericheng 
416269Sericheng static int
417269Sericheng drv_ioc_vlan_info(dls_vlan_t *dvp, void *arg)
418269Sericheng {
419269Sericheng 	dld_ioc_vlan_state_t	*statep = arg;
4200Sstevel@tonic-gate 
421733Skrgopi 	/*
422733Skrgopi 	 * passed buffer space is limited to 65536 bytes. So
423733Skrgopi 	 * copy only the vlans associated with the passed link.
424733Skrgopi 	 */
425*2311Sseb 	if (strcmp(dvp->dv_dlp->dl_name, statep->divp->div_name) == 0 &&
426733Skrgopi 	    dvp->dv_id != 0) {
427733Skrgopi 		if (statep->bytes_left < sizeof (dld_vlan_info_t))
428733Skrgopi 			return (ENOSPC);
429269Sericheng 
430733Skrgopi 		(void) strlcpy(statep->vlanp->dvi_name,
431733Skrgopi 		    dvp->dv_name, IFNAMSIZ);
432733Skrgopi 		statep->divp->div_count++;
433733Skrgopi 		statep->bytes_left -= sizeof (dld_vlan_info_t);
434733Skrgopi 		statep->vlanp += 1;
435733Skrgopi 	}
436269Sericheng 	return (0);
437269Sericheng }
438269Sericheng 
439269Sericheng static void
440269Sericheng drv_ioc_vlan(dld_ctl_str_t *ctls, mblk_t *mp)
441269Sericheng {
442269Sericheng 	dld_ioc_vlan_t		*divp;
443269Sericheng 	dld_ioc_vlan_state_t	state;
444269Sericheng 	int			err = EINVAL;
445269Sericheng 	queue_t			*q = ctls->cs_wq;
446733Skrgopi 	mblk_t			*bp;
447269Sericheng 
448269Sericheng 	if ((err = miocpullup(mp, sizeof (dld_ioc_vlan_t))) != 0)
449269Sericheng 		goto failed;
450269Sericheng 
451733Skrgopi 	if ((bp = msgpullup(mp->b_cont, -1)) == NULL)
452733Skrgopi 		goto failed;
453733Skrgopi 
454733Skrgopi 	freemsg(mp->b_cont);
455733Skrgopi 	mp->b_cont = bp;
456733Skrgopi 	divp = (dld_ioc_vlan_t *)bp->b_rptr;
457733Skrgopi 	divp->div_count = 0;
458733Skrgopi 	state.bytes_left = MBLKL(bp) - sizeof (dld_ioc_vlan_t);
459733Skrgopi 	state.divp = divp;
460269Sericheng 	state.vlanp = (dld_vlan_info_t *)(divp + 1);
461269Sericheng 
462269Sericheng 	err = dls_vlan_walk(drv_ioc_vlan_info, &state);
463269Sericheng 	if (err != 0)
464269Sericheng 		goto failed;
4650Sstevel@tonic-gate 
466269Sericheng 	miocack(q, mp, sizeof (dld_ioc_vlan_t) +
467733Skrgopi 	    state.divp->div_count * sizeof (dld_vlan_info_t), 0);
468269Sericheng 	return;
469269Sericheng 
470269Sericheng failed:
471269Sericheng 	ASSERT(err != 0);
472269Sericheng 	miocnak(q, mp, 0, err);
473269Sericheng }
474269Sericheng 
475269Sericheng 
476269Sericheng /*
477269Sericheng  * Process an IOCTL message received by the control node.
478269Sericheng  */
479269Sericheng static void
480269Sericheng drv_ioc(dld_ctl_str_t *ctls, mblk_t *mp)
481269Sericheng {
482269Sericheng 	uint_t	cmd;
483269Sericheng 
484269Sericheng 	cmd = ((struct iocblk *)mp->b_rptr)->ioc_cmd;
485269Sericheng 	switch (cmd) {
486269Sericheng 	case DLDIOCATTR:
487269Sericheng 		drv_ioc_attr(ctls, mp);
488269Sericheng 		return;
489269Sericheng 	case DLDIOCVLAN:
490269Sericheng 		drv_ioc_vlan(ctls, mp);
491269Sericheng 		return;
492269Sericheng 	default:
493269Sericheng 		miocnak(ctls->cs_wq, mp, 0, ENOTSUP);
494269Sericheng 		return;
495269Sericheng 	}
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate /*
499269Sericheng  * Write side put routine of the dld control node.
5000Sstevel@tonic-gate  */
5010Sstevel@tonic-gate static void
502269Sericheng drv_uw_put(queue_t *q, mblk_t *mp)
5030Sstevel@tonic-gate {
504269Sericheng 	dld_ctl_str_t *ctls = q->q_ptr;
5050Sstevel@tonic-gate 
506269Sericheng 	switch (mp->b_datap->db_type) {
507269Sericheng 	case M_IOCTL:
508269Sericheng 		drv_ioc(ctls, mp);
509269Sericheng 		break;
510269Sericheng 	default:
511269Sericheng 		freemsg(mp);
512269Sericheng 		break;
513269Sericheng 	}
514269Sericheng }
5150Sstevel@tonic-gate 
516269Sericheng /*
517269Sericheng  * Write-side service procedure.
518269Sericheng  */
519269Sericheng void
520269Sericheng drv_uw_srv(queue_t *q)
521269Sericheng {
522269Sericheng 	mblk_t *mp;
5230Sstevel@tonic-gate 
524269Sericheng 	while (mp = getq(q))
525269Sericheng 		drv_uw_put(q, mp);
5260Sstevel@tonic-gate }
527