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