xref: /onnv-gate/usr/src/uts/common/io/softmac/softmac_dev.c (revision 7656:2621e50fdf4a)
15895Syz147064 /*
25895Syz147064  * CDDL HEADER START
35895Syz147064  *
45895Syz147064  * The contents of this file are subject to the terms of the
55895Syz147064  * Common Development and Distribution License (the "License").
65895Syz147064  * You may not use this file except in compliance with the License.
75895Syz147064  *
85895Syz147064  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95895Syz147064  * or http://www.opensolaris.org/os/licensing.
105895Syz147064  * See the License for the specific language governing permissions
115895Syz147064  * and limitations under the License.
125895Syz147064  *
135895Syz147064  * When distributing Covered Code, include this CDDL HEADER in each
145895Syz147064  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155895Syz147064  * If applicable, add the following below this CDDL HEADER, with the
165895Syz147064  * fields enclosed by brackets "[]" replaced with your own identifying
175895Syz147064  * information: Portions Copyright [yyyy] [name of copyright owner]
185895Syz147064  *
195895Syz147064  * CDDL HEADER END
205895Syz147064  */
215895Syz147064 /*
225895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
235895Syz147064  * Use is subject to license terms.
245895Syz147064  */
255895Syz147064 
265895Syz147064 
275895Syz147064 #include <sys/types.h>
285895Syz147064 #include <sys/dld.h>
295895Syz147064 #include <inet/common.h>
305895Syz147064 #include <sys/stropts.h>
315895Syz147064 #include <sys/modctl.h>
325895Syz147064 #include <sys/avl.h>
335895Syz147064 #include <sys/softmac_impl.h>
345895Syz147064 #include <sys/softmac.h>
355895Syz147064 
365895Syz147064 dev_info_t		*softmac_dip = NULL;
375895Syz147064 
385895Syz147064 static int softmac_open(queue_t *, dev_t *, int, int, cred_t *);
395895Syz147064 static int softmac_close(queue_t *);
405895Syz147064 static void softmac_rput(queue_t *, mblk_t *);
415895Syz147064 static void softmac_rsrv(queue_t *);
425895Syz147064 static void softmac_wput(queue_t *, mblk_t *);
435895Syz147064 static void softmac_wsrv(queue_t *);
445895Syz147064 static int softmac_attach(dev_info_t *, ddi_attach_cmd_t);
455895Syz147064 static int softmac_detach(dev_info_t *, ddi_detach_cmd_t);
465895Syz147064 static int softmac_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
475895Syz147064 
485895Syz147064 static struct module_info softmac_modinfo = {
495895Syz147064 	0,
505895Syz147064 	SOFTMAC_DEV_NAME,
515895Syz147064 	0,
525895Syz147064 	INFPSZ,
535895Syz147064 	65536,
545895Syz147064 	1024
555895Syz147064 };
565895Syz147064 
575895Syz147064 /*
585895Syz147064  * hi-water mark is 1 because of the flow control mechanism implemented in
595895Syz147064  * dld.  Refer to the comments in dld_str.c for details.
605895Syz147064  */
615895Syz147064 static struct module_info softmac_dld_modinfo = {
625895Syz147064 	0,
635895Syz147064 	SOFTMAC_DEV_NAME,
645895Syz147064 	0,
655895Syz147064 	INFPSZ,
665895Syz147064 	1,
675895Syz147064 	0
685895Syz147064 };
695895Syz147064 
705895Syz147064 static struct qinit softmac_urinit = {
715895Syz147064 	(pfi_t)softmac_rput,	/* qi_putp */
725895Syz147064 	(pfi_t)softmac_rsrv,	/* qi_srvp */
735895Syz147064 	softmac_open,		/* qi_qopen */
745895Syz147064 	softmac_close,		/* qi_qclose */
755895Syz147064 	NULL,			/* qi_qadmin */
765895Syz147064 	&softmac_modinfo	/* qi_minfo */
775895Syz147064 };
785895Syz147064 
795895Syz147064 static struct qinit softmac_uwinit = {
805895Syz147064 	(pfi_t)softmac_wput,	/* qi_putp */
815895Syz147064 	(pfi_t)softmac_wsrv,	/* qi_srvp */
825895Syz147064 	NULL,			/* qi_qopen */
835895Syz147064 	NULL,			/* qi_qclose */
845895Syz147064 	NULL,			/* qi_qadmin */
855895Syz147064 	&softmac_modinfo	/* qi_minfo */
865895Syz147064 };
875895Syz147064 
885895Syz147064 static struct streamtab softmac_tab = {
895895Syz147064 	&softmac_urinit,	/* st_rdinit */
905895Syz147064 	&softmac_uwinit		/* st_wrinit */
915895Syz147064 };
925895Syz147064 
935895Syz147064 DDI_DEFINE_STREAM_OPS(softmac_ops, nulldev, nulldev, softmac_attach,
94*7656SSherry.Moore@Sun.COM     softmac_detach, nodev, softmac_info, D_MP, &softmac_tab,
95*7656SSherry.Moore@Sun.COM     ddi_quiesce_not_supported);
965895Syz147064 
975895Syz147064 static struct qinit softmac_dld_r_qinit = {
985895Syz147064 	NULL, NULL, dld_open, dld_close, NULL, &softmac_dld_modinfo
995895Syz147064 };
1005895Syz147064 
1015895Syz147064 static struct qinit softmac_dld_w_qinit = {
1025895Syz147064 	(pfi_t)dld_wput, (pfi_t)dld_wsrv, NULL, NULL, NULL,
1035895Syz147064 	&softmac_dld_modinfo
1045895Syz147064 };
1055895Syz147064 
1065895Syz147064 static struct fmodsw softmac_fmodsw = {
1075895Syz147064 	SOFTMAC_DEV_NAME,
1085895Syz147064 	&softmac_tab,
1095895Syz147064 	D_MP
1105895Syz147064 };
1115895Syz147064 
1125895Syz147064 static struct modldrv softmac_modldrv = {
1135895Syz147064 	&mod_driverops,
1145895Syz147064 	"softmac driver",
1155895Syz147064 	&softmac_ops
1165895Syz147064 };
1175895Syz147064 
1185895Syz147064 static struct modlstrmod softmac_modlstrmod = {
1195895Syz147064 	&mod_strmodops,
1205895Syz147064 	"softmac module",
1215895Syz147064 	&softmac_fmodsw
1225895Syz147064 };
1235895Syz147064 
1245895Syz147064 static struct modlinkage softmac_modlinkage = {
1255895Syz147064 	MODREV_1,
1265895Syz147064 	&softmac_modlstrmod,
1275895Syz147064 	&softmac_modldrv,
1285895Syz147064 	NULL
1295895Syz147064 };
1305895Syz147064 
1315895Syz147064 int
1325895Syz147064 _init(void)
1335895Syz147064 {
1345895Syz147064 	int	err;
1355895Syz147064 
1365895Syz147064 	softmac_init();
1375895Syz147064 
1385895Syz147064 	if ((err = mod_install(&softmac_modlinkage)) != 0) {
1395895Syz147064 		softmac_fini();
1405895Syz147064 		return (err);
1415895Syz147064 	}
1425895Syz147064 
1435895Syz147064 	return (0);
1445895Syz147064 }
1455895Syz147064 
1465895Syz147064 int
1475895Syz147064 _fini(void)
1485895Syz147064 {
1495895Syz147064 	int err;
1505895Syz147064 
1515895Syz147064 	if (softmac_busy())
1525895Syz147064 		return (EBUSY);
1535895Syz147064 
1545895Syz147064 	if ((err = mod_remove(&softmac_modlinkage)) != 0)
1555895Syz147064 		return (err);
1565895Syz147064 
1575895Syz147064 	softmac_fini();
1585895Syz147064 
1595895Syz147064 	return (0);
1605895Syz147064 }
1615895Syz147064 
1625895Syz147064 int
1635895Syz147064 _info(struct modinfo *modinfop)
1645895Syz147064 {
1655895Syz147064 	return (mod_info(&softmac_modlinkage, modinfop));
1665895Syz147064 }
1675895Syz147064 
1685895Syz147064 static int
1695895Syz147064 softmac_open(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *credp)
1705895Syz147064 {
1715895Syz147064 	softmac_lower_t	*slp;
1725895Syz147064 	/*
1735895Syz147064 	 * This is a self-cloning driver so that each queue should only
1745895Syz147064 	 * get opened once.
1755895Syz147064 	 */
1765895Syz147064 	if (rq->q_ptr != NULL)
1775895Syz147064 		return (EBUSY);
1785895Syz147064 
1795895Syz147064 	if (sflag == MODOPEN) {
1805895Syz147064 		/*
1815895Syz147064 		 * This is the softmac module pushed over an underlying
1825895Syz147064 		 * legacy device.  Initialize the lower structure.
1835895Syz147064 		 */
1845895Syz147064 		if ((slp = kmem_zalloc(sizeof (*slp), KM_NOSLEEP)) == NULL)
1855895Syz147064 			return (ENOMEM);
1865895Syz147064 
1875895Syz147064 		slp->sl_wq = WR(rq);
1885895Syz147064 		cv_init(&slp->sl_cv, NULL, CV_DRIVER, NULL);
1895895Syz147064 		mutex_init(&slp->sl_mutex, NULL, MUTEX_DRIVER, NULL);
1905895Syz147064 		cv_init(&slp->sl_ctl_cv, NULL, CV_DRIVER, NULL);
1915895Syz147064 		mutex_init(&slp->sl_ctl_mutex, NULL, MUTEX_DRIVER, NULL);
1925895Syz147064 		slp->sl_pending_prim = DL_PRIM_INVAL;
1935895Syz147064 		rq->q_ptr = WR(rq)->q_ptr = slp;
1945895Syz147064 		qprocson(rq);
1955895Syz147064 		return (0);
1965895Syz147064 	}
1975895Syz147064 
1985895Syz147064 	/*
1995895Syz147064 	 * Regular device open of a softmac DLPI node.  We modify
2005895Syz147064 	 * the queues' q_qinfo pointer such that all future STREAMS
2015895Syz147064 	 * operations will go through dld's entry points (including
2025895Syz147064 	 * dld_close()).
2035895Syz147064 	 */
2045895Syz147064 	rq->q_qinfo = &softmac_dld_r_qinit;
2055895Syz147064 	WR(rq)->q_qinfo = &softmac_dld_w_qinit;
2065895Syz147064 	return (dld_open(rq, devp, flag, sflag, credp));
2075895Syz147064 }
2085895Syz147064 
2095895Syz147064 static int
2105895Syz147064 softmac_close(queue_t *rq)
2115895Syz147064 {
2125895Syz147064 	softmac_lower_t	*slp = rq->q_ptr;
2135895Syz147064 
2145895Syz147064 	/*
2155895Syz147064 	 * Call the appropriate delete routine depending on whether this is
2165895Syz147064 	 * a module or device.
2175895Syz147064 	 */
2185895Syz147064 	ASSERT(WR(rq)->q_next != NULL);
2195895Syz147064 
2205895Syz147064 	qprocsoff(rq);
2215895Syz147064 
2225895Syz147064 	slp->sl_softmac = NULL;
2235895Syz147064 	slp->sl_lh = NULL;
2245895Syz147064 
2255895Syz147064 	/*
2265895Syz147064 	 * slp->sl_handle could be non-NULL if it is in the aggregation.
2275895Syz147064 	 */
2285895Syz147064 	slp->sl_handle = (mac_resource_handle_t)NULL;
2295895Syz147064 
2305895Syz147064 	ASSERT(slp->sl_ack_mp == NULL);
2315895Syz147064 	ASSERT(slp->sl_ctl_inprogress == B_FALSE);
2325895Syz147064 	ASSERT(slp->sl_pending_prim == DL_PRIM_INVAL);
2335895Syz147064 	ASSERT(slp->sl_pending_ioctl == B_FALSE);
2345895Syz147064 
2355895Syz147064 	cv_destroy(&slp->sl_cv);
2365895Syz147064 	mutex_destroy(&slp->sl_mutex);
2375895Syz147064 	cv_destroy(&slp->sl_ctl_cv);
2385895Syz147064 	mutex_destroy(&slp->sl_ctl_mutex);
2395895Syz147064 
2405895Syz147064 	kmem_free(slp, sizeof (*slp));
2415895Syz147064 	return (0);
2425895Syz147064 }
2435895Syz147064 
2445895Syz147064 static void
2455895Syz147064 softmac_rput(queue_t *rq, mblk_t *mp)
2465895Syz147064 {
2475895Syz147064 	softmac_lower_t *slp = rq->q_ptr;
2485895Syz147064 	union DL_primitives *dlp;
2495895Syz147064 
2505895Syz147064 	/*
2515895Syz147064 	 * This is the softmac module.
2525895Syz147064 	 */
2535895Syz147064 	ASSERT(WR(rq)->q_next != NULL);
2545895Syz147064 	ASSERT((mp->b_next == NULL) && (mp->b_prev == NULL));
2555895Syz147064 
2565895Syz147064 	switch (DB_TYPE(mp)) {
2575895Syz147064 	case M_DATA:
2585895Syz147064 		/*
2595895Syz147064 		 * Some drivers start to send up packets even if not in the
2605895Syz147064 		 * DL_IDLE state, where sl_softmac is not set yet.  Drop the
2615895Syz147064 		 * packet in this case.
2625895Syz147064 		 */
2635895Syz147064 		if (slp->sl_softmac == NULL) {
2645895Syz147064 			freemsg(mp);
2655895Syz147064 			return;
2665895Syz147064 		}
2675895Syz147064 
2685895Syz147064 		/*
2695895Syz147064 		 * This is the most common case.
2705895Syz147064 		 */
2715895Syz147064 		if (DB_REF(mp) == 1) {
2725895Syz147064 			ASSERT(slp->sl_softmac != NULL);
2735895Syz147064 			/*
2745895Syz147064 			 * We don't need any locks to protect sl_handle
2755895Syz147064 			 * because ip_input() can tolerate if sl_handle
2765895Syz147064 			 * is reset to NULL when DL_CAPAB_POLL is
2775895Syz147064 			 * disabled.
2785895Syz147064 			 */
2795895Syz147064 			mac_rx(slp->sl_softmac->smac_mh, slp->sl_handle, mp);
2805895Syz147064 			return;
2815895Syz147064 		} else {
2825895Syz147064 			softmac_rput_process_data(slp, mp);
2835895Syz147064 		}
2845895Syz147064 		break;
2855895Syz147064 	case M_PROTO:
2865895Syz147064 	case M_PCPROTO:
2875895Syz147064 		if (MBLKL(mp) < sizeof (dlp->dl_primitive)) {
2885895Syz147064 			freemsg(mp);
2895895Syz147064 			break;
2905895Syz147064 		}
2915895Syz147064 		dlp = (union DL_primitives *)mp->b_rptr;
2925895Syz147064 		if (dlp->dl_primitive == DL_UNITDATA_IND) {
2935895Syz147064 			cmn_err(CE_WARN, "got unexpected %s message",
2945895Syz147064 			    dl_primstr(DL_UNITDATA_IND));
2955895Syz147064 			freemsg(mp);
2965895Syz147064 			break;
2975895Syz147064 		}
2985895Syz147064 		/*FALLTHROUGH*/
2995895Syz147064 	default:
3005895Syz147064 		softmac_rput_process_notdata(rq, mp);
3015895Syz147064 		break;
3025895Syz147064 	}
3035895Syz147064 }
3045895Syz147064 
3055895Syz147064 /* ARGSUSED */
3065895Syz147064 static void
3075895Syz147064 softmac_rsrv(queue_t *rq)
3085895Syz147064 {
3095895Syz147064 }
3105895Syz147064 
3115895Syz147064 static void
3125895Syz147064 softmac_wput(queue_t *wq, mblk_t *mp)
3135895Syz147064 {
3145895Syz147064 	/*
3155895Syz147064 	 * This is the softmac module
3165895Syz147064 	 */
3175895Syz147064 	ASSERT(wq->q_next != NULL);
3185895Syz147064 
3195895Syz147064 	switch (DB_TYPE(mp)) {
3205895Syz147064 	case M_IOCTL: {
3215895Syz147064 		struct iocblk		*ioc = (struct iocblk *)mp->b_rptr;
3225895Syz147064 
3235895Syz147064 		switch (ioc->ioc_cmd) {
3245895Syz147064 		case SMAC_IOC_START: {
3255895Syz147064 			softmac_lower_t		*slp = wq->q_ptr;
3265895Syz147064 			smac_ioc_start_t	*arg;
3275895Syz147064 
3285895Syz147064 			if (ioc->ioc_count != sizeof (*arg)) {
3295895Syz147064 				miocnak(wq, mp, 0, EINVAL);
3305895Syz147064 				break;
3315895Syz147064 			}
3325895Syz147064 
3335895Syz147064 			/*
3345895Syz147064 			 * Assign the devname and perstream handle of the
3355895Syz147064 			 * specific lower stream and return it as a part
3365895Syz147064 			 * of the ioctl.
3375895Syz147064 			 */
3385895Syz147064 			arg = (smac_ioc_start_t *)mp->b_cont->b_rptr;
3395895Syz147064 			arg->si_slp = slp;
3405895Syz147064 
3415895Syz147064 			miocack(wq, mp, sizeof (*arg), 0);
3425895Syz147064 			break;
3435895Syz147064 		}
3445895Syz147064 		default:
3455895Syz147064 			miocnak(wq, mp, 0, EINVAL);
3465895Syz147064 			break;
3475895Syz147064 		}
3485895Syz147064 		break;
3495895Syz147064 	}
3505895Syz147064 	default:
3515895Syz147064 		freemsg(mp);
3525895Syz147064 		break;
3535895Syz147064 	}
3545895Syz147064 }
3555895Syz147064 
3565895Syz147064 static void
3575895Syz147064 softmac_wsrv(queue_t *wq)
3585895Syz147064 {
3595895Syz147064 	softmac_lower_t *slp = wq->q_ptr;
3605895Syz147064 
3615895Syz147064 	/*
3625895Syz147064 	 * This is the softmac module
3635895Syz147064 	 */
3645895Syz147064 	ASSERT(wq->q_next != NULL);
3655895Syz147064 
3665895Syz147064 	/*
3675895Syz147064 	 * Inform that the tx resource is available; mac_tx_update() will
3685895Syz147064 	 * inform all the upper streams sharing this lower stream.
3695895Syz147064 	 */
3705895Syz147064 	if (slp->sl_softmac != NULL)
3715895Syz147064 		mac_tx_update(slp->sl_softmac->smac_mh);
3725895Syz147064 }
3735895Syz147064 
3745895Syz147064 static int
3755895Syz147064 softmac_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
3765895Syz147064 {
3775895Syz147064 	ASSERT(ddi_get_instance(dip) == 0);
3785895Syz147064 
3795895Syz147064 	if (cmd != DDI_ATTACH)
3805895Syz147064 		return (DDI_FAILURE);
3815895Syz147064 
3825895Syz147064 	softmac_dip = dip;
3835895Syz147064 
3845895Syz147064 	return (DDI_SUCCESS);
3855895Syz147064 }
3865895Syz147064 
3875895Syz147064 /* ARGSUSED */
3885895Syz147064 static int
3895895Syz147064 softmac_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3905895Syz147064 {
3915895Syz147064 	if (cmd != DDI_DETACH)
3925895Syz147064 		return (DDI_FAILURE);
3935895Syz147064 
3945895Syz147064 	softmac_dip = NULL;
3955895Syz147064 	return (DDI_SUCCESS);
3965895Syz147064 }
3975895Syz147064 
3985895Syz147064 /* ARGSUSED */
3995895Syz147064 static int
4005895Syz147064 softmac_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
4015895Syz147064 {
4025895Syz147064 	switch (infocmd) {
4035895Syz147064 	case DDI_INFO_DEVT2DEVINFO:
4045895Syz147064 		if (softmac_dip != NULL) {
4055895Syz147064 			*result = softmac_dip;
4065895Syz147064 			return (DDI_SUCCESS);
4075895Syz147064 		}
4085895Syz147064 		break;
4095895Syz147064 
4105895Syz147064 	case DDI_INFO_DEVT2INSTANCE:
4115895Syz147064 		*result = NULL;
4125895Syz147064 		return (DDI_SUCCESS);
4135895Syz147064 
4145895Syz147064 	}
4155895Syz147064 
4165895Syz147064 	return (DDI_FAILURE);
4175895Syz147064 }
418