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 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 #pragma ident "%Z%%M% %I% %E% SMI" 40 41 /* 42 * Kernel TLI-like function to initialize a transport 43 * endpoint using the protocol specified. 44 * 45 * Returns: 46 * 0 on success and "tiptr" is set to a valid transport pointer, 47 * else a positive error code. 48 */ 49 50 #include <sys/param.h> 51 #include <sys/types.h> 52 #include <sys/proc.h> 53 #include <sys/file.h> 54 #include <sys/user.h> 55 #include <sys/vnode.h> 56 #include <sys/errno.h> 57 #include <sys/stream.h> 58 #include <sys/ioctl.h> 59 #include <sys/stropts.h> 60 #include <sys/strsubr.h> 61 #include <sys/tihdr.h> 62 #include <sys/timod.h> 63 #include <sys/tiuser.h> 64 #include <sys/t_kuser.h> 65 #include <sys/kmem.h> 66 #include <sys/cmn_err.h> 67 68 static t_scalar_t _t_setsize(t_scalar_t); 69 70 int 71 t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr) 72 { 73 int madefp = 0; 74 struct T_info_ack inforeq; 75 int retval; 76 vnode_t *vp; 77 struct strioctl strioc; 78 int error; 79 TIUSER *ntiptr; 80 int rtries = 0; 81 82 /* 83 * Special case for install: miniroot needs to be able to access files 84 * via NFS as though it were always in the global zone. 85 */ 86 if (nfs_global_client_only != 0) 87 cr = kcred; 88 89 KTLILOG(2, "t_kopen: fp %x, ", fp); 90 KTLILOG(2, "rdev %x, ", rdev); 91 KTLILOG(2, "flags %x\n", flags); 92 93 *tiptr = NULL; 94 error = 0; 95 retval = 0; 96 if (fp == NULL) { 97 if (rdev == 0 || rdev == NODEV) { 98 KTLILOG(1, "t_kopen: null device\n", 0); 99 return (EINVAL); 100 } 101 102 /* 103 * allocate a file pointer, but 104 * no file descripter. 105 */ 106 if ((error = falloc(NULL, flags, &fp, NULL)) != 0) { 107 KTLILOG(1, "t_kopen: falloc: %d\n", error); 108 return (error); 109 } 110 111 /* Install proper cred in file */ 112 if (cr != fp->f_cred) { 113 crhold(cr); 114 crfree(fp->f_cred); 115 fp->f_cred = cr; 116 } 117 118 vp = makespecvp(rdev, VCHR); 119 120 /* 121 * this will call the streams open for us. 122 * Want to retry if error is EAGAIN, the streams open routine 123 * might fail due to temporarely out of memory. 124 */ 125 do { 126 if ((error = VOP_OPEN(&vp, flags, cr, NULL)) 127 == 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