xref: /onnv-gate/usr/src/uts/common/io/softmac/softmac_dev.c (revision 5895:f251acdd9bdc)
1*5895Syz147064 /*
2*5895Syz147064  * CDDL HEADER START
3*5895Syz147064  *
4*5895Syz147064  * The contents of this file are subject to the terms of the
5*5895Syz147064  * Common Development and Distribution License (the "License").
6*5895Syz147064  * You may not use this file except in compliance with the License.
7*5895Syz147064  *
8*5895Syz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5895Syz147064  * or http://www.opensolaris.org/os/licensing.
10*5895Syz147064  * See the License for the specific language governing permissions
11*5895Syz147064  * and limitations under the License.
12*5895Syz147064  *
13*5895Syz147064  * When distributing Covered Code, include this CDDL HEADER in each
14*5895Syz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5895Syz147064  * If applicable, add the following below this CDDL HEADER, with the
16*5895Syz147064  * fields enclosed by brackets "[]" replaced with your own identifying
17*5895Syz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5895Syz147064  *
19*5895Syz147064  * CDDL HEADER END
20*5895Syz147064  */
21*5895Syz147064 /*
22*5895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*5895Syz147064  * Use is subject to license terms.
24*5895Syz147064  */
25*5895Syz147064 
26*5895Syz147064 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*5895Syz147064 
28*5895Syz147064 #include <sys/types.h>
29*5895Syz147064 #include <sys/dld.h>
30*5895Syz147064 #include <inet/common.h>
31*5895Syz147064 #include <sys/stropts.h>
32*5895Syz147064 #include <sys/modctl.h>
33*5895Syz147064 #include <sys/avl.h>
34*5895Syz147064 #include <sys/softmac_impl.h>
35*5895Syz147064 #include <sys/softmac.h>
36*5895Syz147064 
37*5895Syz147064 dev_info_t		*softmac_dip = NULL;
38*5895Syz147064 
39*5895Syz147064 static int softmac_open(queue_t *, dev_t *, int, int, cred_t *);
40*5895Syz147064 static int softmac_close(queue_t *);
41*5895Syz147064 static void softmac_rput(queue_t *, mblk_t *);
42*5895Syz147064 static void softmac_rsrv(queue_t *);
43*5895Syz147064 static void softmac_wput(queue_t *, mblk_t *);
44*5895Syz147064 static void softmac_wsrv(queue_t *);
45*5895Syz147064 static int softmac_attach(dev_info_t *, ddi_attach_cmd_t);
46*5895Syz147064 static int softmac_detach(dev_info_t *, ddi_detach_cmd_t);
47*5895Syz147064 static int softmac_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
48*5895Syz147064 
49*5895Syz147064 static struct module_info softmac_modinfo = {
50*5895Syz147064 	0,
51*5895Syz147064 	SOFTMAC_DEV_NAME,
52*5895Syz147064 	0,
53*5895Syz147064 	INFPSZ,
54*5895Syz147064 	65536,
55*5895Syz147064 	1024
56*5895Syz147064 };
57*5895Syz147064 
58*5895Syz147064 /*
59*5895Syz147064  * hi-water mark is 1 because of the flow control mechanism implemented in
60*5895Syz147064  * dld.  Refer to the comments in dld_str.c for details.
61*5895Syz147064  */
62*5895Syz147064 static struct module_info softmac_dld_modinfo = {
63*5895Syz147064 	0,
64*5895Syz147064 	SOFTMAC_DEV_NAME,
65*5895Syz147064 	0,
66*5895Syz147064 	INFPSZ,
67*5895Syz147064 	1,
68*5895Syz147064 	0
69*5895Syz147064 };
70*5895Syz147064 
71*5895Syz147064 static struct qinit softmac_urinit = {
72*5895Syz147064 	(pfi_t)softmac_rput,	/* qi_putp */
73*5895Syz147064 	(pfi_t)softmac_rsrv,	/* qi_srvp */
74*5895Syz147064 	softmac_open,		/* qi_qopen */
75*5895Syz147064 	softmac_close,		/* qi_qclose */
76*5895Syz147064 	NULL,			/* qi_qadmin */
77*5895Syz147064 	&softmac_modinfo	/* qi_minfo */
78*5895Syz147064 };
79*5895Syz147064 
80*5895Syz147064 static struct qinit softmac_uwinit = {
81*5895Syz147064 	(pfi_t)softmac_wput,	/* qi_putp */
82*5895Syz147064 	(pfi_t)softmac_wsrv,	/* qi_srvp */
83*5895Syz147064 	NULL,			/* qi_qopen */
84*5895Syz147064 	NULL,			/* qi_qclose */
85*5895Syz147064 	NULL,			/* qi_qadmin */
86*5895Syz147064 	&softmac_modinfo	/* qi_minfo */
87*5895Syz147064 };
88*5895Syz147064 
89*5895Syz147064 static struct streamtab softmac_tab = {
90*5895Syz147064 	&softmac_urinit,	/* st_rdinit */
91*5895Syz147064 	&softmac_uwinit		/* st_wrinit */
92*5895Syz147064 };
93*5895Syz147064 
94*5895Syz147064 DDI_DEFINE_STREAM_OPS(softmac_ops, nulldev, nulldev, softmac_attach,
95*5895Syz147064     softmac_detach, nodev, softmac_info, D_MP, &softmac_tab);
96*5895Syz147064 
97*5895Syz147064 static struct qinit softmac_dld_r_qinit = {
98*5895Syz147064 	NULL, NULL, dld_open, dld_close, NULL, &softmac_dld_modinfo
99*5895Syz147064 };
100*5895Syz147064 
101*5895Syz147064 static struct qinit softmac_dld_w_qinit = {
102*5895Syz147064 	(pfi_t)dld_wput, (pfi_t)dld_wsrv, NULL, NULL, NULL,
103*5895Syz147064 	&softmac_dld_modinfo
104*5895Syz147064 };
105*5895Syz147064 
106*5895Syz147064 static struct fmodsw softmac_fmodsw = {
107*5895Syz147064 	SOFTMAC_DEV_NAME,
108*5895Syz147064 	&softmac_tab,
109*5895Syz147064 	D_MP
110*5895Syz147064 };
111*5895Syz147064 
112*5895Syz147064 static struct modldrv softmac_modldrv = {
113*5895Syz147064 	&mod_driverops,
114*5895Syz147064 	"softmac driver",
115*5895Syz147064 	&softmac_ops
116*5895Syz147064 };
117*5895Syz147064 
118*5895Syz147064 static struct modlstrmod softmac_modlstrmod = {
119*5895Syz147064 	&mod_strmodops,
120*5895Syz147064 	"softmac module",
121*5895Syz147064 	&softmac_fmodsw
122*5895Syz147064 };
123*5895Syz147064 
124*5895Syz147064 static struct modlinkage softmac_modlinkage = {
125*5895Syz147064 	MODREV_1,
126*5895Syz147064 	&softmac_modlstrmod,
127*5895Syz147064 	&softmac_modldrv,
128*5895Syz147064 	NULL
129*5895Syz147064 };
130*5895Syz147064 
131*5895Syz147064 int
132*5895Syz147064 _init(void)
133*5895Syz147064 {
134*5895Syz147064 	int	err;
135*5895Syz147064 
136*5895Syz147064 	softmac_init();
137*5895Syz147064 
138*5895Syz147064 	if ((err = mod_install(&softmac_modlinkage)) != 0) {
139*5895Syz147064 		softmac_fini();
140*5895Syz147064 		return (err);
141*5895Syz147064 	}
142*5895Syz147064 
143*5895Syz147064 	return (0);
144*5895Syz147064 }
145*5895Syz147064 
146*5895Syz147064 int
147*5895Syz147064 _fini(void)
148*5895Syz147064 {
149*5895Syz147064 	int err;
150*5895Syz147064 
151*5895Syz147064 	if (softmac_busy())
152*5895Syz147064 		return (EBUSY);
153*5895Syz147064 
154*5895Syz147064 	if ((err = mod_remove(&softmac_modlinkage)) != 0)
155*5895Syz147064 		return (err);
156*5895Syz147064 
157*5895Syz147064 	softmac_fini();
158*5895Syz147064 
159*5895Syz147064 	return (0);
160*5895Syz147064 }
161*5895Syz147064 
162*5895Syz147064 int
163*5895Syz147064 _info(struct modinfo *modinfop)
164*5895Syz147064 {
165*5895Syz147064 	return (mod_info(&softmac_modlinkage, modinfop));
166*5895Syz147064 }
167*5895Syz147064 
168*5895Syz147064 static int
169*5895Syz147064 softmac_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
170*5895Syz147064 {
171*5895Syz147064 	softmac_lower_t	*slp;
172*5895Syz147064 	/*
173*5895Syz147064 	 * This is a self-cloning driver so that each queue should only
174*5895Syz147064 	 * get opened once.
175*5895Syz147064 	 */
176*5895Syz147064 	if (rq->q_ptr != NULL)
177*5895Syz147064 		return (EBUSY);
178*5895Syz147064 
179*5895Syz147064 	if (sflag == MODOPEN) {
180*5895Syz147064 		/*
181*5895Syz147064 		 * This is the softmac module pushed over an underlying
182*5895Syz147064 		 * legacy device.  Initialize the lower structure.
183*5895Syz147064 		 */
184*5895Syz147064 		if ((slp = kmem_zalloc(sizeof (*slp), KM_NOSLEEP)) == NULL)
185*5895Syz147064 			return (ENOMEM);
186*5895Syz147064 
187*5895Syz147064 		slp->sl_wq = WR(rq);
188*5895Syz147064 		cv_init(&slp->sl_cv, NULL, CV_DRIVER, NULL);
189*5895Syz147064 		mutex_init(&slp->sl_mutex, NULL, MUTEX_DRIVER, NULL);
190*5895Syz147064 		cv_init(&slp->sl_ctl_cv, NULL, CV_DRIVER, NULL);
191*5895Syz147064 		mutex_init(&slp->sl_ctl_mutex, NULL, MUTEX_DRIVER, NULL);
192*5895Syz147064 		slp->sl_pending_prim = DL_PRIM_INVAL;
193*5895Syz147064 		rq->q_ptr = WR(rq)->q_ptr = slp;
194*5895Syz147064 		qprocson(rq);
195*5895Syz147064 		return (0);
196*5895Syz147064 	}
197*5895Syz147064 
198*5895Syz147064 	/*
199*5895Syz147064 	 * Regular device open of a softmac DLPI node.  We modify
200*5895Syz147064 	 * the queues' q_qinfo pointer such that all future STREAMS
201*5895Syz147064 	 * operations will go through dld's entry points (including
202*5895Syz147064 	 * dld_close()).
203*5895Syz147064 	 */
204*5895Syz147064 	rq->q_qinfo = &softmac_dld_r_qinit;
205*5895Syz147064 	WR(rq)->q_qinfo = &softmac_dld_w_qinit;
206*5895Syz147064 	return (dld_open(rq, devp, flag, sflag, credp));
207*5895Syz147064 }
208*5895Syz147064 
209*5895Syz147064 static int
210*5895Syz147064 softmac_close(queue_t *rq)
211*5895Syz147064 {
212*5895Syz147064 	softmac_lower_t	*slp = rq->q_ptr;
213*5895Syz147064 
214*5895Syz147064 	/*
215*5895Syz147064 	 * Call the appropriate delete routine depending on whether this is
216*5895Syz147064 	 * a module or device.
217*5895Syz147064 	 */
218*5895Syz147064 	ASSERT(WR(rq)->q_next != NULL);
219*5895Syz147064 
220*5895Syz147064 	qprocsoff(rq);
221*5895Syz147064 
222*5895Syz147064 	slp->sl_softmac = NULL;
223*5895Syz147064 	slp->sl_lh = NULL;
224*5895Syz147064 
225*5895Syz147064 	/*
226*5895Syz147064 	 * slp->sl_handle could be non-NULL if it is in the aggregation.
227*5895Syz147064 	 */
228*5895Syz147064 	slp->sl_handle = (mac_resource_handle_t)NULL;
229*5895Syz147064 
230*5895Syz147064 	ASSERT(slp->sl_ack_mp == NULL);
231*5895Syz147064 	ASSERT(slp->sl_ctl_inprogress == B_FALSE);
232*5895Syz147064 	ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL);
233*5895Syz147064 	ASSERT(slp->sl_pending_ioctl == B_FALSE);
234*5895Syz147064 
235*5895Syz147064 	cv_destroy(&slp->sl_cv);
236*5895Syz147064 	mutex_destroy(&slp->sl_mutex);
237*5895Syz147064 	cv_destroy(&slp->sl_ctl_cv);
238*5895Syz147064 	mutex_destroy(&slp->sl_ctl_mutex);
239*5895Syz147064 
240*5895Syz147064 	kmem_free(slp, sizeof (*slp));
241*5895Syz147064 	return (0);
242*5895Syz147064 }
243*5895Syz147064 
244*5895Syz147064 static void
245*5895Syz147064 softmac_rput(queue_t *rq, mblk_t *mp)
246*5895Syz147064 {
247*5895Syz147064 	softmac_lower_t *slp = rq->q_ptr;
248*5895Syz147064 	union DL_primitives *dlp;
249*5895Syz147064 
250*5895Syz147064 	/*
251*5895Syz147064 	 * This is the softmac module.
252*5895Syz147064 	 */
253*5895Syz147064 	ASSERT(WR(rq)->q_next != NULL);
254*5895Syz147064 	ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL));
255*5895Syz147064 
256*5895Syz147064 	switch (DB_TYPE(mp)) {
257*5895Syz147064 	case M_DATA:
258*5895Syz147064 		/*
259*5895Syz147064 		 * Some drivers start to send up packets even if not in the
260*5895Syz147064 		 * DL_IDLE state, where sl_softmac is not set yet.  Drop the
261*5895Syz147064 		 * packet in this case.
262*5895Syz147064 		 */
263*5895Syz147064 		if (slp->sl_softmac == NULL) {
264*5895Syz147064 			freemsg(mp);
265*5895Syz147064 			return;
266*5895Syz147064 		}
267*5895Syz147064 
268*5895Syz147064 		/*
269*5895Syz147064 		 * This is the most common case.
270*5895Syz147064 		 */
271*5895Syz147064 		if (DB_REF(mp) == 1) {
272*5895Syz147064 			ASSERT(slp->sl_softmac != NULL);
273*5895Syz147064 			/*
274*5895Syz147064 			 * We don't need any locks to protect sl_handle
275*5895Syz147064 			 * because ip_input() can tolerate if sl_handle
276*5895Syz147064 			 * is reset to NULL when DL_CAPAB_POLL is
277*5895Syz147064 			 * disabled.
278*5895Syz147064 			 */
279*5895Syz147064 			mac_rx(slp->sl_softmac->smac_mh, slp->sl_handle, mp);
280*5895Syz147064 			return;
281*5895Syz147064 		} else {
282*5895Syz147064 			softmac_rput_process_data(slp, mp);
283*5895Syz147064 		}
284*5895Syz147064 		break;
285*5895Syz147064 	case M_PROTO:
286*5895Syz147064 	case M_PCPROTO:
287*5895Syz147064 		if (MBLKL(mp) < sizeof (dlp->dl_primitive)) {
288*5895Syz147064 			freemsg(mp);
289*5895Syz147064 			break;
290*5895Syz147064 		}
291*5895Syz147064 		dlp = (union DL_primitives *)mp->b_rptr;
292*5895Syz147064 		if (dlp->dl_primitive == DL_UNITDATA_IND) {
293*5895Syz147064 			cmn_err(CE_WARN, "got unexpected %s message",
294*5895Syz147064 			    dl_primstr(DL_UNITDATA_IND));
295*5895Syz147064 			freemsg(mp);
296*5895Syz147064 			break;
297*5895Syz147064 		}
298*5895Syz147064 		/*FALLTHROUGH*/
299*5895Syz147064 	default:
300*5895Syz147064 		softmac_rput_process_notdata(rq, mp);
301*5895Syz147064 		break;
302*5895Syz147064 	}
303*5895Syz147064 }
304*5895Syz147064 
305*5895Syz147064 /* ARGSUSED */
306*5895Syz147064 static void
307*5895Syz147064 softmac_rsrv(queue_t *rq)
308*5895Syz147064 {
309*5895Syz147064 }
310*5895Syz147064 
311*5895Syz147064 static void
312*5895Syz147064 softmac_wput(queue_t *wq, mblk_t *mp)
313*5895Syz147064 {
314*5895Syz147064 	/*
315*5895Syz147064 	 * This is the softmac module
316*5895Syz147064 	 */
317*5895Syz147064 	ASSERT(wq->q_next != NULL);
318*5895Syz147064 
319*5895Syz147064 	switch (DB_TYPE(mp)) {
320*5895Syz147064 	case M_IOCTL: {
321*5895Syz147064 		struct iocblk		*ioc = (struct iocblk *)mp->b_rptr;
322*5895Syz147064 
323*5895Syz147064 		switch (ioc->ioc_cmd) {
324*5895Syz147064 		case SMAC_IOC_START: {
325*5895Syz147064 			softmac_lower_t		*slp = wq->q_ptr;
326*5895Syz147064 			smac_ioc_start_t	*arg;
327*5895Syz147064 
328*5895Syz147064 			if (ioc->ioc_count != sizeof (*arg)) {
329*5895Syz147064 				miocnak(wq, mp, 0, EINVAL);
330*5895Syz147064 				break;
331*5895Syz147064 			}
332*5895Syz147064 
333*5895Syz147064 			/*
334*5895Syz147064 			 * Assign the devname and perstream handle of the
335*5895Syz147064 			 * specific lower stream and return it as a part
336*5895Syz147064 			 * of the ioctl.
337*5895Syz147064 			 */
338*5895Syz147064 			arg = (smac_ioc_start_t *)mp->b_cont->b_rptr;
339*5895Syz147064 			arg->si_slp = slp;
340*5895Syz147064 
341*5895Syz147064 			miocack(wq, mp, sizeof (*arg), 0);
342*5895Syz147064 			break;
343*5895Syz147064 		}
344*5895Syz147064 		default:
345*5895Syz147064 			miocnak(wq, mp, 0, EINVAL);
346*5895Syz147064 			break;
347*5895Syz147064 		}
348*5895Syz147064 		break;
349*5895Syz147064 	}
350*5895Syz147064 	default:
351*5895Syz147064 		freemsg(mp);
352*5895Syz147064 		break;
353*5895Syz147064 	}
354*5895Syz147064 }
355*5895Syz147064 
356*5895Syz147064 static void
357*5895Syz147064 softmac_wsrv(queue_t *wq)
358*5895Syz147064 {
359*5895Syz147064 	softmac_lower_t *slp = wq->q_ptr;
360*5895Syz147064 
361*5895Syz147064 	/*
362*5895Syz147064 	 * This is the softmac module
363*5895Syz147064 	 */
364*5895Syz147064 	ASSERT(wq->q_next != NULL);
365*5895Syz147064 
366*5895Syz147064 	/*
367*5895Syz147064 	 * Inform that the tx resource is available; mac_tx_update() will
368*5895Syz147064 	 * inform all the upper streams sharing this lower stream.
369*5895Syz147064 	 */
370*5895Syz147064 	if (slp->sl_softmac != NULL)
371*5895Syz147064 		mac_tx_update(slp->sl_softmac->smac_mh);
372*5895Syz147064 }
373*5895Syz147064 
374*5895Syz147064 static int
375*5895Syz147064 softmac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
376*5895Syz147064 {
377*5895Syz147064 	ASSERT(ddi_get_instance(dip) == 0);
378*5895Syz147064 
379*5895Syz147064 	if (cmd != DDI_ATTACH)
380*5895Syz147064 		return (DDI_FAILURE);
381*5895Syz147064 
382*5895Syz147064 	softmac_dip = dip;
383*5895Syz147064 
384*5895Syz147064 	return (DDI_SUCCESS);
385*5895Syz147064 }
386*5895Syz147064 
387*5895Syz147064 /* ARGSUSED */
388*5895Syz147064 static int
389*5895Syz147064 softmac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
390*5895Syz147064 {
391*5895Syz147064 	if (cmd != DDI_DETACH)
392*5895Syz147064 		return (DDI_FAILURE);
393*5895Syz147064 
394*5895Syz147064 	softmac_dip = NULL;
395*5895Syz147064 	return (DDI_SUCCESS);
396*5895Syz147064 }
397*5895Syz147064 
398*5895Syz147064 /* ARGSUSED */
399*5895Syz147064 static int
400*5895Syz147064 softmac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
401*5895Syz147064 {
402*5895Syz147064 	switch (infocmd) {
403*5895Syz147064 	case DDI_INFO_DEVT2DEVINFO:
404*5895Syz147064 		if (softmac_dip != NULL) {
405*5895Syz147064 			*result = softmac_dip;
406*5895Syz147064 			return (DDI_SUCCESS);
407*5895Syz147064 		}
408*5895Syz147064 		break;
409*5895Syz147064 
410*5895Syz147064 	case DDI_INFO_DEVT2INSTANCE:
411*5895Syz147064 		*result = NULL;
412*5895Syz147064 		return (DDI_SUCCESS);
413*5895Syz147064 
414*5895Syz147064 	}
415*5895Syz147064 
416*5895Syz147064 	return (DDI_FAILURE);
417*5895Syz147064 }
418