xref: /illumos-gate/usr/src/uts/common/inet/dlpistub/dlpistub.c (revision e11c3f44f531fdff80941ce57c065d2ae861cefc)
1*e11c3f44Smeem /*
2*e11c3f44Smeem  * CDDL HEADER START
3*e11c3f44Smeem  *
4*e11c3f44Smeem  * The contents of this file are subject to the terms of the
5*e11c3f44Smeem  * Common Development and Distribution License (the "License").
6*e11c3f44Smeem  * You may not use this file except in compliance with the License.
7*e11c3f44Smeem  *
8*e11c3f44Smeem  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*e11c3f44Smeem  * or http://www.opensolaris.org/os/licensing.
10*e11c3f44Smeem  * See the License for the specific language governing permissions
11*e11c3f44Smeem  * and limitations under the License.
12*e11c3f44Smeem  *
13*e11c3f44Smeem  * When distributing Covered Code, include this CDDL HEADER in each
14*e11c3f44Smeem  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*e11c3f44Smeem  * If applicable, add the following below this CDDL HEADER, with the
16*e11c3f44Smeem  * fields enclosed by brackets "[]" replaced with your own identifying
17*e11c3f44Smeem  * information: Portions Copyright [yyyy] [name of copyright owner]
18*e11c3f44Smeem  *
19*e11c3f44Smeem  * CDDL HEADER END
20*e11c3f44Smeem  */
21*e11c3f44Smeem /*
22*e11c3f44Smeem  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23*e11c3f44Smeem  * Use is subject to license terms.
24*e11c3f44Smeem  */
25*e11c3f44Smeem 
26*e11c3f44Smeem /*
27*e11c3f44Smeem  * DLPI stub driver; currently supports VNI and IPMP stub devices.
28*e11c3f44Smeem  */
29*e11c3f44Smeem 
30*e11c3f44Smeem #include <sys/conf.h>
31*e11c3f44Smeem #include <sys/ddi.h>
32*e11c3f44Smeem #include <sys/sunddi.h>
33*e11c3f44Smeem #include <sys/dlpi.h>
34*e11c3f44Smeem #include <sys/stat.h>
35*e11c3f44Smeem #include <sys/strsun.h>
36*e11c3f44Smeem #include <sys/stropts.h>
37*e11c3f44Smeem #include <sys/types.h>
38*e11c3f44Smeem #include <sys/id_space.h>
39*e11c3f44Smeem #include <sys/sysmacros.h>
40*e11c3f44Smeem #include <sys/kmem.h>
41*e11c3f44Smeem #include <sys/modctl.h>
42*e11c3f44Smeem #include <sys/mkdev.h>
43*e11c3f44Smeem #include <sys/sdt.h>
44*e11c3f44Smeem 
45*e11c3f44Smeem #include "dlpistub_impl.h"
46*e11c3f44Smeem 
47*e11c3f44Smeem static id_space_t *ds_minors;
48*e11c3f44Smeem static dev_info_t *ds_dip;
49*e11c3f44Smeem 
50*e11c3f44Smeem /*
51*e11c3f44Smeem  * DL_INFO_ACK template.
52*e11c3f44Smeem  */
53*e11c3f44Smeem static dl_info_ack_t ds_infoack = {
54*e11c3f44Smeem 	DL_INFO_ACK,	/* dl_primitive */
55*e11c3f44Smeem 	0,		/* dl_max_sdu */
56*e11c3f44Smeem 	0,		/* dl_min_sdu */
57*e11c3f44Smeem 	0,		/* dl_addr_length */
58*e11c3f44Smeem 	0,		/* dl_mac_type */
59*e11c3f44Smeem 	0,		/* dl_reserved */
60*e11c3f44Smeem 	0,		/* dl_current_state */
61*e11c3f44Smeem 	0,		/* dl_sap_length */
62*e11c3f44Smeem 	DL_CLDLS,	/* dl_service_mode */
63*e11c3f44Smeem 	0,		/* dl_qos_length */
64*e11c3f44Smeem 	0,		/* dl_qos_offset */
65*e11c3f44Smeem 	0,		/* dl_qos_range_length */
66*e11c3f44Smeem 	0,		/* dl_qos_range_offset */
67*e11c3f44Smeem 	DL_STYLE2,	/* dl_provider_style */
68*e11c3f44Smeem 	0,		/* dl_addr_offset */
69*e11c3f44Smeem 	DL_VERSION_2,	/* dl_version */
70*e11c3f44Smeem 	0,		/* dl_brdcst_addr_length */
71*e11c3f44Smeem 	0,		/* dl_brdcst_addr_offset */
72*e11c3f44Smeem 	0		/* dl_growth */
73*e11c3f44Smeem };
74*e11c3f44Smeem 
75*e11c3f44Smeem static int
ds_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)76*e11c3f44Smeem ds_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
77*e11c3f44Smeem {
78*e11c3f44Smeem 	if (cmd != DDI_ATTACH)
79*e11c3f44Smeem 		return (DDI_FAILURE);
80*e11c3f44Smeem 
81*e11c3f44Smeem 	if (ddi_create_minor_node(dip, "vni", S_IFCHR, DS_MINOR_VNI,
82*e11c3f44Smeem 	    DDI_PSEUDO, 0) == DDI_FAILURE ||
83*e11c3f44Smeem 	    ddi_create_minor_node(dip, "ipmpstub", S_IFCHR, DS_MINOR_IPMP,
84*e11c3f44Smeem 	    DDI_PSEUDO, 0) == DDI_FAILURE) {
85*e11c3f44Smeem 		ddi_remove_minor_node(dip, NULL);
86*e11c3f44Smeem 		cmn_err(CE_NOTE, "ds_attach: cannot create minor nodes");
87*e11c3f44Smeem 		return (DDI_FAILURE);
88*e11c3f44Smeem 	}
89*e11c3f44Smeem 
90*e11c3f44Smeem 	ds_dip = dip;
91*e11c3f44Smeem 	ds_minors = id_space_create("ds_minors", DS_MINOR_START, MAXMIN32);
92*e11c3f44Smeem 	return (DDI_SUCCESS);
93*e11c3f44Smeem }
94*e11c3f44Smeem 
95*e11c3f44Smeem static int
ds_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)96*e11c3f44Smeem ds_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
97*e11c3f44Smeem {
98*e11c3f44Smeem 	if (cmd != DDI_DETACH)
99*e11c3f44Smeem 		return (DDI_FAILURE);
100*e11c3f44Smeem 
101*e11c3f44Smeem 	id_space_destroy(ds_minors);
102*e11c3f44Smeem 	ds_minors = NULL;
103*e11c3f44Smeem 	ASSERT(dip == ds_dip);
104*e11c3f44Smeem 	ddi_remove_minor_node(dip, NULL);
105*e11c3f44Smeem 	ds_dip = NULL;
106*e11c3f44Smeem 	return (DDI_SUCCESS);
107*e11c3f44Smeem }
108*e11c3f44Smeem 
109*e11c3f44Smeem /* ARGSUSED */
110*e11c3f44Smeem static int
ds_devinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)111*e11c3f44Smeem ds_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
112*e11c3f44Smeem {
113*e11c3f44Smeem 	int error = DDI_FAILURE;
114*e11c3f44Smeem 
115*e11c3f44Smeem 	switch (infocmd) {
116*e11c3f44Smeem 	case DDI_INFO_DEVT2INSTANCE:
117*e11c3f44Smeem 		*result = (void *)0;
118*e11c3f44Smeem 		error = DDI_SUCCESS;
119*e11c3f44Smeem 		break;
120*e11c3f44Smeem 	case DDI_INFO_DEVT2DEVINFO:
121*e11c3f44Smeem 		if (ds_dip != NULL) {
122*e11c3f44Smeem 			*result = ds_dip;
123*e11c3f44Smeem 			error = DDI_SUCCESS;
124*e11c3f44Smeem 		}
125*e11c3f44Smeem 		break;
126*e11c3f44Smeem 	}
127*e11c3f44Smeem 	return (error);
128*e11c3f44Smeem }
129*e11c3f44Smeem 
130*e11c3f44Smeem /* ARGSUSED */
131*e11c3f44Smeem static int
ds_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)132*e11c3f44Smeem ds_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
133*e11c3f44Smeem {
134*e11c3f44Smeem 	int type;
135*e11c3f44Smeem 	dlpistub_t *dsp;
136*e11c3f44Smeem 
137*e11c3f44Smeem 	if (sflag == CLONEOPEN || sflag == MODOPEN)
138*e11c3f44Smeem 		return (EINVAL);
139*e11c3f44Smeem 
140*e11c3f44Smeem 	if (q->q_ptr != NULL)
141*e11c3f44Smeem 		return (0);
142*e11c3f44Smeem 
143*e11c3f44Smeem 	switch (getminor(*devp)) {
144*e11c3f44Smeem 	case DS_MINOR_VNI:
145*e11c3f44Smeem 		type = SUNW_DL_VNI;
146*e11c3f44Smeem 		break;
147*e11c3f44Smeem 	case DS_MINOR_IPMP:
148*e11c3f44Smeem 		type = SUNW_DL_IPMP;
149*e11c3f44Smeem 		break;
150*e11c3f44Smeem 	default:
151*e11c3f44Smeem 		return (ENXIO);
152*e11c3f44Smeem 	}
153*e11c3f44Smeem 
154*e11c3f44Smeem 	dsp = kmem_zalloc(sizeof (dlpistub_t), KM_SLEEP);
155*e11c3f44Smeem 	dsp->ds_type = type;
156*e11c3f44Smeem 	dsp->ds_minor = (minor_t)id_alloc(ds_minors);
157*e11c3f44Smeem 	dsp->ds_state = DL_UNATTACHED;
158*e11c3f44Smeem 	*devp = makedevice(getmajor(*devp), dsp->ds_minor);
159*e11c3f44Smeem 	q->q_ptr = WR(q)->q_ptr = dsp;
160*e11c3f44Smeem 	qprocson(q);
161*e11c3f44Smeem 
162*e11c3f44Smeem 	return (0);
163*e11c3f44Smeem }
164*e11c3f44Smeem 
165*e11c3f44Smeem /* ARGSUSED */
166*e11c3f44Smeem static int
ds_close(queue_t * q,int flag,cred_t * credp)167*e11c3f44Smeem ds_close(queue_t *q, int flag, cred_t *credp)
168*e11c3f44Smeem {
169*e11c3f44Smeem 	dlpistub_t	*dsp = q->q_ptr;
170*e11c3f44Smeem 
171*e11c3f44Smeem 	qprocsoff(q);
172*e11c3f44Smeem 	q->q_ptr = WR(q)->q_ptr = NULL;
173*e11c3f44Smeem 
174*e11c3f44Smeem 	id_free(ds_minors, dsp->ds_minor);
175*e11c3f44Smeem 	kmem_free(dsp, sizeof (dlpistub_t));
176*e11c3f44Smeem 
177*e11c3f44Smeem 	return (0);
178*e11c3f44Smeem }
179*e11c3f44Smeem 
180*e11c3f44Smeem static int
ds_badprim(queue_t * q,mblk_t * mp,t_scalar_t prim)181*e11c3f44Smeem ds_badprim(queue_t *q, mblk_t *mp, t_scalar_t prim)
182*e11c3f44Smeem {
183*e11c3f44Smeem 	dlerrorack(q, mp, prim, DL_BADPRIM, 0);
184*e11c3f44Smeem 	return (0);
185*e11c3f44Smeem }
186*e11c3f44Smeem 
187*e11c3f44Smeem static int
ds_outstate(queue_t * q,mblk_t * mp,t_scalar_t prim)188*e11c3f44Smeem ds_outstate(queue_t *q, mblk_t *mp, t_scalar_t prim)
189*e11c3f44Smeem {
190*e11c3f44Smeem 	dlerrorack(q, mp, prim, DL_OUTSTATE, 0);
191*e11c3f44Smeem 	return (0);
192*e11c3f44Smeem }
193*e11c3f44Smeem 
194*e11c3f44Smeem static int
ds_wput(queue_t * q,mblk_t * mp)195*e11c3f44Smeem ds_wput(queue_t *q, mblk_t *mp)
196*e11c3f44Smeem {
197*e11c3f44Smeem 	union DL_primitives	*dlp;
198*e11c3f44Smeem 	dl_info_ack_t		*dlip;
199*e11c3f44Smeem 	dlpistub_t		*dsp = q->q_ptr;
200*e11c3f44Smeem 	t_scalar_t		prim;
201*e11c3f44Smeem 
202*e11c3f44Smeem 	switch (DB_TYPE(mp)) {
203*e11c3f44Smeem 	case M_PROTO:
204*e11c3f44Smeem 	case M_PCPROTO:
205*e11c3f44Smeem 		if (MBLKL(mp) < sizeof (t_scalar_t)) {
206*e11c3f44Smeem 			dlerrorack(q, mp, DL_PRIM_INVAL, DL_UNSUPPORTED, 0);
207*e11c3f44Smeem 			return (0);
208*e11c3f44Smeem 		}
209*e11c3f44Smeem 
210*e11c3f44Smeem 		dlp = (void *)mp->b_rptr;
211*e11c3f44Smeem 		prim = dlp->dl_primitive;
212*e11c3f44Smeem 		switch (prim) {
213*e11c3f44Smeem 		case DL_ATTACH_REQ:
214*e11c3f44Smeem 			if (MBLKL(mp) < DL_ATTACH_REQ_SIZE)
215*e11c3f44Smeem 				return (ds_badprim(q, mp, prim));
216*e11c3f44Smeem 
217*e11c3f44Smeem 			if (dsp->ds_state != DL_UNATTACHED)
218*e11c3f44Smeem 				return (ds_outstate(q, mp, prim));
219*e11c3f44Smeem 
220*e11c3f44Smeem 			dsp->ds_state = DL_UNBOUND;
221*e11c3f44Smeem 			dlokack(q, mp, DL_ATTACH_REQ);
222*e11c3f44Smeem 			break;
223*e11c3f44Smeem 
224*e11c3f44Smeem 		case DL_BIND_REQ:
225*e11c3f44Smeem 			if (MBLKL(mp) < DL_BIND_REQ_SIZE)
226*e11c3f44Smeem 				return (ds_badprim(q, mp, prim));
227*e11c3f44Smeem 
228*e11c3f44Smeem 			if (dsp->ds_state != DL_UNBOUND)
229*e11c3f44Smeem 				return (ds_outstate(q, mp, prim));
230*e11c3f44Smeem 
231*e11c3f44Smeem 			dsp->ds_state = DL_IDLE;
232*e11c3f44Smeem 			dlbindack(q, mp, dlp->bind_req.dl_sap, NULL, 0, 0, 0);
233*e11c3f44Smeem 			break;
234*e11c3f44Smeem 
235*e11c3f44Smeem 		case DL_INFO_REQ:
236*e11c3f44Smeem 			if (MBLKL(mp) < DL_INFO_REQ_SIZE)
237*e11c3f44Smeem 				return (ds_badprim(q, mp, prim));
238*e11c3f44Smeem 
239*e11c3f44Smeem 			mp = mexchange(q, mp, sizeof (dl_info_ack_t),
240*e11c3f44Smeem 			    M_PCPROTO, DL_INFO_ACK);
241*e11c3f44Smeem 			if (mp != NULL) {
242*e11c3f44Smeem 				dlip = (void *)mp->b_rptr;
243*e11c3f44Smeem 				*dlip = ds_infoack;
244*e11c3f44Smeem 				dlip->dl_mac_type = dsp->ds_type;
245*e11c3f44Smeem 				dlip->dl_current_state = dsp->ds_state;
246*e11c3f44Smeem 				qreply(q, mp);
247*e11c3f44Smeem 			}
248*e11c3f44Smeem 			break;
249*e11c3f44Smeem 
250*e11c3f44Smeem 		case DL_PHYS_ADDR_REQ:
251*e11c3f44Smeem 			if (MBLKL(mp) < DL_PHYS_ADDR_REQ_SIZE)
252*e11c3f44Smeem 				return (ds_badprim(q, mp, prim));
253*e11c3f44Smeem 
254*e11c3f44Smeem 			dlphysaddrack(q, mp, NULL, 0);
255*e11c3f44Smeem 			break;
256*e11c3f44Smeem 
257*e11c3f44Smeem 		case DL_UNBIND_REQ:
258*e11c3f44Smeem 			if (MBLKL(mp) < DL_UNBIND_REQ_SIZE)
259*e11c3f44Smeem 				return (ds_badprim(q, mp, prim));
260*e11c3f44Smeem 
261*e11c3f44Smeem 			if (dsp->ds_state != DL_IDLE)
262*e11c3f44Smeem 				return (ds_outstate(q, mp, prim));
263*e11c3f44Smeem 
264*e11c3f44Smeem 			dsp->ds_state = DL_UNBOUND;
265*e11c3f44Smeem 			dlokack(q, mp, DL_UNBIND_REQ);
266*e11c3f44Smeem 			break;
267*e11c3f44Smeem 
268*e11c3f44Smeem 		case DL_DETACH_REQ:
269*e11c3f44Smeem 			if (MBLKL(mp) < DL_DETACH_REQ_SIZE)
270*e11c3f44Smeem 				return (ds_badprim(q, mp, prim));
271*e11c3f44Smeem 
272*e11c3f44Smeem 			if (dsp->ds_state != DL_UNBOUND)
273*e11c3f44Smeem 				return (ds_outstate(q, mp, prim));
274*e11c3f44Smeem 
275*e11c3f44Smeem 			dsp->ds_state = DL_UNATTACHED;
276*e11c3f44Smeem 			dlokack(q, mp, DL_DETACH_REQ);
277*e11c3f44Smeem 			break;
278*e11c3f44Smeem 
279*e11c3f44Smeem 		case DL_UNITDATA_REQ:
280*e11c3f44Smeem 			DTRACE_PROBE2(dlpistub__data, dlpistub_t *, dsp,
281*e11c3f44Smeem 			    mblk_t *, mp);
282*e11c3f44Smeem 			freemsg(mp);
283*e11c3f44Smeem 			break;
284*e11c3f44Smeem 
285*e11c3f44Smeem 		default:
286*e11c3f44Smeem 			dlerrorack(q, mp, prim, DL_UNSUPPORTED, 0);
287*e11c3f44Smeem 		}
288*e11c3f44Smeem 		break;
289*e11c3f44Smeem 
290*e11c3f44Smeem 	case M_IOCTL:
291*e11c3f44Smeem 		miocnak(q, mp, 0, EINVAL);
292*e11c3f44Smeem 		break;
293*e11c3f44Smeem 
294*e11c3f44Smeem 	case M_FLUSH:
295*e11c3f44Smeem 		*mp->b_rptr &= ~FLUSHW;
296*e11c3f44Smeem 		if (*mp->b_rptr & FLUSHR)
297*e11c3f44Smeem 			qreply(q, mp);
298*e11c3f44Smeem 		else
299*e11c3f44Smeem 			freemsg(mp);
300*e11c3f44Smeem 		break;
301*e11c3f44Smeem 	default:
302*e11c3f44Smeem 		freemsg(mp);
303*e11c3f44Smeem 		break;
304*e11c3f44Smeem 	}
305*e11c3f44Smeem 
306*e11c3f44Smeem 	return (0);
307*e11c3f44Smeem }
308*e11c3f44Smeem 
309*e11c3f44Smeem static struct module_info ds_minfo = {
310*e11c3f44Smeem 	DS_IDNUM,	/* mi_idnum */
311*e11c3f44Smeem 	"dlpistub",	/* mi_idname */
312*e11c3f44Smeem 	0,		/* mi_minpsz */
313*e11c3f44Smeem 	INFPSZ,		/* mi_maxpsz */
314*e11c3f44Smeem 	0,		/* mi_hiwat */
315*e11c3f44Smeem 	0,		/* mi_lowat */
316*e11c3f44Smeem };
317*e11c3f44Smeem 
318*e11c3f44Smeem static struct qinit ds_rinit = {
319*e11c3f44Smeem 	NULL,		/* qi_putp */
320*e11c3f44Smeem 	NULL,		/* qi_srvp */
321*e11c3f44Smeem 	ds_open,	/* qi_qopen */
322*e11c3f44Smeem 	ds_close,	/* qi_qclose */
323*e11c3f44Smeem 	NULL,		/* qi_qadmin */
324*e11c3f44Smeem 	&ds_minfo,	/* qi_minfo */
325*e11c3f44Smeem };
326*e11c3f44Smeem 
327*e11c3f44Smeem static struct qinit ds_winit = {
328*e11c3f44Smeem 	ds_wput,	/* qi_putp */
329*e11c3f44Smeem 	NULL,		/* qi_srvp */
330*e11c3f44Smeem 	NULL,		/* qi_qopen */
331*e11c3f44Smeem 	NULL,		/* qi_qclose */
332*e11c3f44Smeem 	NULL,		/* qi_qadmin */
333*e11c3f44Smeem 	&ds_minfo,	/* qi_minfo */
334*e11c3f44Smeem };
335*e11c3f44Smeem 
336*e11c3f44Smeem static struct streamtab ds_info = {
337*e11c3f44Smeem 	&ds_rinit,	/* st_rdinit */
338*e11c3f44Smeem 	&ds_winit	/* st_wrinit */
339*e11c3f44Smeem };
340*e11c3f44Smeem 
341*e11c3f44Smeem DDI_DEFINE_STREAM_OPS(ds_ops, nulldev, nulldev, ds_attach, ds_detach,
342*e11c3f44Smeem     nodev, ds_devinfo, D_MP|D_MTPERMOD, &ds_info, ddi_quiesce_not_supported);
343*e11c3f44Smeem 
344*e11c3f44Smeem static struct modldrv modldrv = {
345*e11c3f44Smeem 	&mod_driverops,
346*e11c3f44Smeem 	"DLPI stub driver",
347*e11c3f44Smeem 	&ds_ops,
348*e11c3f44Smeem };
349*e11c3f44Smeem 
350*e11c3f44Smeem static struct modlinkage modlinkage = {
351*e11c3f44Smeem 	MODREV_1, &modldrv, NULL
352*e11c3f44Smeem };
353*e11c3f44Smeem 
354*e11c3f44Smeem int
_init(void)355*e11c3f44Smeem _init(void)
356*e11c3f44Smeem {
357*e11c3f44Smeem 	return (mod_install(&modlinkage));
358*e11c3f44Smeem }
359*e11c3f44Smeem 
360*e11c3f44Smeem int
_fini(void)361*e11c3f44Smeem _fini(void)
362*e11c3f44Smeem {
363*e11c3f44Smeem 	return (mod_remove(&modlinkage));
364*e11c3f44Smeem }
365*e11c3f44Smeem 
366*e11c3f44Smeem int
_info(struct modinfo * modinfop)367*e11c3f44Smeem _info(struct modinfo *modinfop)
368*e11c3f44Smeem {
369*e11c3f44Smeem 	return (mod_info(&modlinkage, modinfop));
370*e11c3f44Smeem }
371