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