1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma ident "%Z%%M% %I% %E% SMI" /* from S5R4 1.10 */ 32 33 /* 34 * Clone Driver. 35 */ 36 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/errno.h> 40 #include <sys/signal.h> 41 #include <sys/vfs.h> 42 #include <sys/vnode.h> 43 #include <sys/pcb.h> 44 #include <sys/user.h> 45 #include <sys/stropts.h> 46 #include <sys/stream.h> 47 #include <sys/errno.h> 48 #include <sys/sysinfo.h> 49 #include <sys/systm.h> 50 #include <sys/conf.h> 51 #include <sys/debug.h> 52 #include <sys/cred.h> 53 #include <sys/mkdev.h> 54 #include <sys/open.h> 55 #include <sys/strsubr.h> 56 #include <sys/ddi.h> 57 #include <sys/sunddi.h> 58 #include <sys/modctl.h> 59 #include <sys/policy.h> 60 61 int clnopen(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *crp); 62 63 static struct module_info clnm_info = { 0, "CLONE", 0, 0, 0, 0 }; 64 static struct qinit clnrinit = { NULL, NULL, clnopen, NULL, NULL, &clnm_info, 65 NULL }; 66 static struct qinit clnwinit = { NULL, NULL, NULL, NULL, NULL, &clnm_info, 67 NULL }; 68 struct streamtab clninfo = { &clnrinit, &clnwinit }; 69 70 static int cln_info(dev_info_t *, ddi_info_cmd_t, void *, void **); 71 static int cln_attach(dev_info_t *, ddi_attach_cmd_t); 72 static dev_info_t *cln_dip; /* private copy of devinfo pointer */ 73 74 #define CLONE_CONF_FLAG (D_NEW|D_MP) 75 76 DDI_DEFINE_STREAM_OPS(clone_ops, nulldev, nulldev, cln_attach, nodev, nodev, \ 77 cln_info, CLONE_CONF_FLAG, &clninfo); 78 79 /* 80 * Module linkage information for the kernel. 81 */ 82 83 static struct modldrv modldrv = { 84 &mod_driverops, /* Type of module. This one is a pseudo driver */ 85 "Clone Pseudodriver 'clone'", 86 &clone_ops, /* driver ops */ 87 }; 88 89 static struct modlinkage modlinkage = { 90 MODREV_1, 91 (void *)&modldrv, 92 NULL 93 }; 94 95 96 int 97 _init(void) 98 { 99 return (mod_install(&modlinkage)); 100 } 101 102 int 103 _fini(void) 104 { 105 /* 106 * Since the clone driver's reference count is unreliable, 107 * make sure we are never unloaded. 108 */ 109 return (EBUSY); 110 } 111 112 int 113 _info(struct modinfo *modinfop) 114 { 115 return (mod_info(&modlinkage, modinfop)); 116 } 117 118 /* ARGSUSED */ 119 static int 120 cln_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 121 { 122 cln_dip = devi; 123 return (DDI_SUCCESS); 124 } 125 126 /* ARGSUSED */ 127 static int 128 cln_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 129 void **result) 130 { 131 int error; 132 133 switch (infocmd) { 134 case DDI_INFO_DEVT2DEVINFO: 135 if (cln_dip == NULL) { 136 error = DDI_FAILURE; 137 } else { 138 *result = (void *)cln_dip; 139 error = DDI_SUCCESS; 140 } 141 break; 142 case DDI_INFO_DEVT2INSTANCE: 143 *result = (void *)0; 144 error = DDI_SUCCESS; 145 break; 146 default: 147 error = DDI_FAILURE; 148 } 149 return (error); 150 } 151 152 /* 153 * Clone open. Maj is the major device number of the streams 154 * device to open. Look up the device in the cdevsw[]. Attach 155 * its qinit structures to the read and write queues and call its 156 * open with the sflag set to CLONEOPEN. Swap in a new vnode with 157 * the real device number constructed from either 158 * a) for old-style drivers: 159 * maj and the minor returned by the device open, or 160 * b) for new-style drivers: 161 * the whole dev passed back as a reference parameter 162 * from the device open. 163 */ 164 int 165 clnopen(queue_t *rq, dev_t *devp, int flag, int sflag, cred_t *crp) 166 { 167 struct streamtab *str; 168 dev_t newdev; 169 int error = 0; 170 major_t maj; 171 minor_t emaj; 172 struct qinit *rinit, *winit; 173 cdevsw_impl_t *dp; 174 uint32_t qflag; 175 uint32_t sqtype; 176 perdm_t *dmp; 177 vnode_t *vp; 178 179 if (sflag) 180 return (ENXIO); 181 182 /* 183 * Get the device to open. 184 */ 185 emaj = getminor(*devp); /* minor is major for a cloned driver */ 186 maj = etoimajor(emaj); /* get internal major of cloned driver */ 187 188 if (maj >= devcnt) 189 return (ENXIO); 190 191 /* 192 * NOTE We call ddi_hold_installed_driver() here to attach 193 * all instances of the driver, since we do not know 194 * a priori which instance the Stream is associated with. 195 * 196 * For Style-2 network drivers, we know that the association 197 * happens at DL_ATTACH time. For other types of drivers, 198 * open probably requires attaching instance 0 (pseudo dip). 199 * 200 * To eliminate ddi_hold_installed_driver(), the following 201 * should happen: 202 * 203 * - GLD be modified to include gld_init(). The driver will 204 * register information for gld_open() to succeed. It will 205 * also inform framework if driver assigns instance=PPA. 206 * - ddi_hold_devi_by_instance() be modified to actively 207 * attach the instance via top-down enumeration. 208 */ 209 if (ddi_hold_installed_driver(maj) == NULL) 210 return (ENXIO); 211 212 if ((str = STREAMSTAB(maj)) == NULL) { 213 ddi_rele_driver(maj); 214 return (ENXIO); 215 } 216 217 newdev = makedevice(emaj, 0); /* create new style device number */ 218 219 /* 220 * Check for security here. For DLPI style 2 network 221 * drivers, we need to apply the default network policy. 222 * Clone is weird in that the network driver isn't loaded 223 * and attached at spec_open() time, we need to load the 224 * driver to see if it is a network driver. Hence, we 225 * check security here (after ddi_hold_installed_driver 226 * call above). 227 */ 228 vp = makespecvp(newdev, VCHR); 229 error = secpolicy_spec_open(crp, vp, flag); 230 VN_RELE(vp); 231 if (error) { 232 ddi_rele_driver(maj); 233 return (error); 234 } 235 236 /* 237 * Save so that we can restore the q on failure. 238 */ 239 rinit = rq->q_qinfo; 240 winit = WR(rq)->q_qinfo; 241 ASSERT(rq->q_syncq->sq_type == (SQ_CI|SQ_CO)); 242 ASSERT((rq->q_flag & QMT_TYPEMASK) == QMTSAFE); 243 244 dp = &devimpl[maj]; 245 ASSERT(str == dp->d_str); 246 247 qflag = dp->d_qflag; 248 sqtype = dp->d_sqtype; 249 250 /* create perdm_t if needed */ 251 if (NEED_DM(dp->d_dmp, qflag)) 252 dp->d_dmp = hold_dm(str, qflag, sqtype); 253 254 dmp = dp->d_dmp; 255 256 /* 257 * Set the syncq state what qattach started off with. This is safe 258 * since no other thread can access this queue at this point 259 * (stream open, close, push, and pop are single threaded 260 * by the framework.) 261 */ 262 leavesq(rq->q_syncq, SQ_OPENCLOSE); 263 264 /* 265 * Substitute the real qinit values for the current ones. 266 */ 267 /* setq might sleep in kmem_alloc - avoid holding locks. */ 268 setq(rq, str->st_rdinit, str->st_wrinit, dmp, qflag, sqtype, B_FALSE); 269 270 /* 271 * Open the attached module or driver. 272 * 273 * If there is an outer perimeter get exclusive access during 274 * the open procedure. 275 * Bump up the reference count on the queue. 276 */ 277 entersq(rq->q_syncq, SQ_OPENCLOSE); 278 279 /* 280 * Call the device open with the stream flag CLONEOPEN. The device 281 * will either fail this or return the device number. 282 */ 283 error = (*rq->q_qinfo->qi_qopen)(rq, &newdev, flag, CLONEOPEN, crp); 284 if (error != 0) 285 goto failed; 286 287 *devp = newdev; 288 if (getmajor(newdev) != emaj) 289 goto bad_major; 290 291 return (0); 292 293 bad_major: 294 /* 295 * Close the device 296 */ 297 (*rq->q_qinfo->qi_qclose)(rq, flag, crp); 298 299 #ifdef DEBUG 300 cmn_err(CE_NOTE, "cannot clone major number %d(%s)->%d", emaj, 301 ddi_major_to_name(emaj), getmajor(newdev)); 302 #endif 303 error = ENXIO; 304 305 failed: 306 /* 307 * open failed; pretty up to look like original 308 * queue. 309 */ 310 if (backq(WR(rq)) && backq(WR(rq))->q_next == WR(rq)) 311 qprocsoff(rq); 312 leavesq(rq->q_syncq, SQ_OPENCLOSE); 313 rq->q_next = WR(rq)->q_next = NULL; 314 ASSERT(flush_syncq(rq->q_syncq, rq) == 0); 315 ASSERT(flush_syncq(WR(rq)->q_syncq, WR(rq)) == 0); 316 rq->q_ptr = WR(rq)->q_ptr = NULL; 317 /* setq might sleep in kmem_alloc - avoid holding locks. */ 318 setq(rq, rinit, winit, NULL, QMTSAFE, SQ_CI|SQ_CO, 319 B_FALSE); 320 321 /* Restore back to what qattach will expect */ 322 entersq(rq->q_syncq, SQ_OPENCLOSE); 323 324 ddi_rele_driver(maj); 325 return (error); 326 } 327