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
t_kopen(file_t * fp,dev_t rdev,int flags,TIUSER ** tiptr,cred_t * cr)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
_t_setsize(t_scalar_t infosize)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