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