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 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * Kernel TLI-like function to initialize a transport 44 * endpoint using the protocol specified. 45 * 46 * Returns: 47 * 0 on success and "tiptr" is set to a valid transport pointer, 48 * else a positive error code. 49 */ 50 51 #include <sys/param.h> 52 #include <sys/types.h> 53 #include <sys/proc.h> 54 #include <sys/file.h> 55 #include <sys/user.h> 56 #include <sys/vnode.h> 57 #include <sys/errno.h> 58 #include <sys/stream.h> 59 #include <sys/ioctl.h> 60 #include <sys/stropts.h> 61 #include <sys/strsubr.h> 62 #include <sys/tihdr.h> 63 #include <sys/timod.h> 64 #include <sys/tiuser.h> 65 #include <sys/t_kuser.h> 66 #include <sys/kmem.h> 67 #include <sys/cmn_err.h> 68 69 static t_scalar_t _t_setsize(t_scalar_t); 70 71 int 72 t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr) 73 { 74 int madefp = 0; 75 struct T_info_ack inforeq; 76 int retval; 77 vnode_t *vp; 78 struct strioctl strioc; 79 int error; 80 TIUSER *ntiptr; 81 int rtries = 0; 82 83 /* 84 * Special case for install: miniroot needs to be able to access files 85 * via NFS as though it were always in the global zone. 86 */ 87 if (nfs_global_client_only != 0) 88 cr = kcred; 89 90 KTLILOG(2, "t_kopen: fp %x, ", fp); 91 KTLILOG(2, "rdev %x, ", rdev); 92 KTLILOG(2, "flags %x\n", flags); 93 94 *tiptr = NULL; 95 error = 0; 96 retval = 0; 97 if (fp == NULL) { 98 if (rdev == 0 || rdev == NODEV) { 99 KTLILOG(1, "t_kopen: null device\n", 0); 100 return (EINVAL); 101 } 102 103 /* 104 * allocate a file pointer, but 105 * no file descripter. 106 */ 107 if ((error = falloc(NULL, flags, &fp, NULL)) != 0) { 108 KTLILOG(1, "t_kopen: falloc: %d\n", error); 109 return (error); 110 } 111 112 /* Install proper cred in file */ 113 if (cr != fp->f_cred) { 114 crhold(cr); 115 crfree(fp->f_cred); 116 fp->f_cred = cr; 117 } 118 119 vp = makespecvp(rdev, VCHR); 120 121 /* 122 * this will call the streams open for us. 123 * Want to retry if error is EAGAIN, the streams open routine 124 * might fail due to temporarely out of memory. 125 */ 126 do { 127 if ((error = VOP_OPEN(&vp, flags, cr)) == EAGAIN) { 128 (void) delay(hz); 129 } 130 } while (error == EAGAIN && ++rtries < 5); 131 132 if (error) { 133 KTLILOG(1, "t_kopen: VOP_OPEN: %d\n", error); 134 unfalloc(fp); 135 VN_RELE(vp); 136 return (error); 137 } 138 /* 139 * fp is completely initialized so drop the write lock. 140 * I actually don't need any locking on fp in here since 141 * there is no fd pointing at it. However, since I could 142 * call closef if there is an error and closef requires 143 * the fp read locked, I will acquire the read lock here 144 * and make sure I release it before I leave this routine. 145 */ 146 fp->f_vnode = vp; 147 mutex_exit(&fp->f_tlock); 148 149 madefp = 1; 150 } else { 151 vp = fp->f_vnode; 152 } 153 154 if (vp->v_stream == NULL) { 155 if (madefp) 156 (void) closef(fp); 157 KTLILOG(1, "t_kopen: not a streams device\n", 0); 158 return (ENOSTR); 159 } 160 161 /* 162 * allocate a new transport structure 163 */ 164 ntiptr = kmem_alloc(TIUSERSZ, KM_SLEEP); 165 ntiptr->fp = fp; 166 ntiptr->flags = madefp ? MADE_FP : 0; 167 168 KTLILOG(2, "t_kopen: vp %x, ", vp); 169 KTLILOG(2, "stp %x\n", vp->v_stream); 170 171 /* 172 * see if TIMOD is already pushed 173 */ 174 error = strioctl(vp, I_FIND, (intptr_t)"timod", 0, K_TO_K, cr, &retval); 175 if (error) { 176 kmem_free(ntiptr, TIUSERSZ); 177 if (madefp) 178 (void) closef(fp); 179 KTLILOG(1, "t_kopen: strioctl(I_FIND, timod): %d\n", error); 180 return (error); 181 } 182 183 if (retval == 0) { 184 tryagain: 185 error = strioctl(vp, I_PUSH, (intptr_t)"timod", 0, K_TO_K, cr, 186 &retval); 187 if (error) { 188 switch (error) { 189 case ENOSPC: 190 case EAGAIN: 191 case ENOSR: 192 /* 193 * This probably means the master file 194 * should be tuned. 195 */ 196 cmn_err(CE_WARN, 197 "t_kopen: I_PUSH of timod failed, error %d\n", 198 error); 199 (void) delay(hz); 200 error = 0; 201 goto tryagain; 202 203 default: 204 kmem_free(ntiptr, TIUSERSZ); 205 if (madefp) 206 (void) closef(fp); 207 KTLILOG(1, "t_kopen: I_PUSH (timod): %d", 208 error); 209 return (error); 210 } 211 } 212 } 213 214 inforeq.PRIM_type = T_INFO_REQ; 215 strioc.ic_cmd = TI_GETINFO; 216 strioc.ic_timout = 0; 217 strioc.ic_dp = (char *)&inforeq; 218 strioc.ic_len = (int)sizeof (struct T_info_req); 219 220 error = strdoioctl(vp->v_stream, &strioc, FNATIVE, K_TO_K, cr, &retval); 221 if (error) { 222 kmem_free(ntiptr, TIUSERSZ); 223 if (madefp) 224 (void) closef(fp); 225 KTLILOG(1, "t_kopen: strdoioctl(T_INFO_REQ): %d\n", error); 226 return (error); 227 } 228 229 if (retval) { 230 if ((retval & 0xff) == TSYSERR) 231 error = (retval >> 8) & 0xff; 232 else 233 error = t_tlitosyserr(retval & 0xff); 234 kmem_free(ntiptr, TIUSERSZ); 235 if (madefp) 236 (void) closef(fp); 237 KTLILOG(1, "t_kopen: strdoioctl(T_INFO_REQ): retval: 0x%x\n", 238 retval); 239 return (error); 240 } 241 242 if (strioc.ic_len != sizeof (struct T_info_ack)) { 243 kmem_free(ntiptr, TIUSERSZ); 244 if (madefp) 245 (void) closef(fp); 246 KTLILOG(1, 247 "t_kopen: strioc.ic_len != sizeof (struct T_info_ack): %d\n", 248 strioc.ic_len); 249 return (EPROTO); 250 } 251 252 ntiptr->tp_info.addr = _t_setsize(inforeq.ADDR_size); 253 ntiptr->tp_info.options = _t_setsize(inforeq.OPT_size); 254 ntiptr->tp_info.tsdu = _t_setsize(inforeq.TSDU_size); 255 ntiptr->tp_info.etsdu = _t_setsize(inforeq.ETSDU_size); 256 ntiptr->tp_info.connect = _t_setsize(inforeq.CDATA_size); 257 ntiptr->tp_info.discon = _t_setsize(inforeq.DDATA_size); 258 ntiptr->tp_info.servtype = inforeq.SERV_type; 259 260 *tiptr = ntiptr; 261 262 return (0); 263 } 264 265 #define DEFSIZE 128 266 267 static t_scalar_t 268 _t_setsize(t_scalar_t infosize) 269 { 270 switch (infosize) { 271 case -1: 272 return (DEFSIZE); 273 case -2: 274 return (0); 275 default: 276 return (infosize); 277 } 278 } 279