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 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
26 * Copyright 2024 RackTop Systems, Inc.
27 */
28
29 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
31
32 /*
33 * University Copyright- Copyright (c) 1982, 1986, 1988
34 * The Regents of the University of California
35 * All Rights Reserved
36 *
37 * University Acknowledgment- Portions of this document are derived from
38 * software developed by the University of California, Berkeley, and its
39 * contributors.
40 */
41
42 /*
43 * Kernel TLI-like functions
44 */
45
46 #include <sys/param.h>
47 #include <sys/types.h>
48 #include <sys/proc.h>
49 #include <sys/file.h>
50 #include <sys/filio.h>
51 #include <sys/user.h>
52 #include <sys/vnode.h>
53 #include <sys/cmn_err.h>
54 #include <sys/errno.h>
55 #include <sys/kmem.h>
56 #include <sys/fcntl.h>
57 #include <sys/ioctl.h>
58 #include <sys/socket.h>
59 #include <sys/stream.h>
60 #include <sys/strsubr.h>
61 #include <sys/strsun.h>
62 #include <sys/tihdr.h>
63 #include <sys/timod.h>
64 #include <sys/tiuser.h>
65 #include <sys/t_kuser.h>
66
67 #include <errno.h>
68 #include <stropts.h>
69 #include <unistd.h>
70
71 /*
72 * While <xti.h> is the perferred interface, we're simulating the
73 * (in-kernel) kTLI here, which forces sys/tiuser.h on us, so just
74 * use the older <tiuser.h> for the simulation.
75 */
76 #include <tiuser.h>
77
78 #include "fake_fio.h"
79
80 /* Size of mblks for tli_recv */
81 #define FKTLI_RCV_SZ 4096
82
83 /*
84 * Translate a TLI error into a system error as best we can.
85 */
86 static const int tli_errs[] = {
87 0, /* no error */
88 EADDRNOTAVAIL, /* TBADADDR */
89 ENOPROTOOPT, /* TBADOPT */
90 EACCES, /* TACCES */
91 EBADF, /* TBADF */
92 EADDRNOTAVAIL, /* TNOADDR */
93 EPROTO, /* TOUTSTATE */
94 EPROTO, /* TBADSEQ */
95 ENOSYS, /* TSYSERR */
96 EPROTO, /* TLOOK */
97 EMSGSIZE, /* TBADDATA */
98 EMSGSIZE, /* TBUFOVFLW */
99 EPROTO, /* TFLOW */
100 EWOULDBLOCK, /* TNODATA */
101 EPROTO, /* TNODIS */
102 EPROTO, /* TNOUDERR */
103 EINVAL, /* TBADFLAG */
104 EPROTO, /* TNOREL */
105 EOPNOTSUPP, /* TNOTSUPPORT */
106 EPROTO, /* TSTATECHNG */
107 };
108
109 static int
tlitosyserr(int terr)110 tlitosyserr(int terr)
111 {
112 if (terr < 0 || (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0]))))
113 return (EPROTO);
114 else
115 return (tli_errs[terr]);
116 }
117
118 /*
119 * Note: This implementation is specific to the needs of the callers in
120 * uts/common/fs/smbclnt/netsmb/smb_trantcp.c
121 */
122 /* ARGSUSED */
123 int
t_kopen(file_t * fp,dev_t rdev,int flags,TIUSER ** tiptr,cred_t * cr)124 t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr)
125 {
126 boolean_t madefp = B_FALSE;
127 TIUSER *tiu;
128 int fd;
129 int rc;
130
131 *tiptr = NULL;
132
133 if (fp == NULL) {
134 /*
135 * create a socket endpoint
136 * dev is actualy AF
137 */
138 char *devnm;
139 switch (rdev) {
140 case AF_INET:
141 devnm = "/dev/tcp";
142 break;
143 case AF_INET6:
144 devnm = "/dev/tcp6";
145 break;
146 default:
147 cmn_err(CE_NOTE, "t_kopen: bad device");
148 return (EINVAL);
149 }
150
151 fd = t_open(devnm, O_RDWR, NULL);
152 if (fd < 0) {
153 rc = t_errno;
154 cmn_err(CE_NOTE, "t_kopen: t_open terr=%d", rc);
155 return (tlitosyserr(rc));
156 }
157
158 /*
159 * allocate a file pointer...
160 */
161 fp = file_getf(fd);
162 madefp = B_TRUE;
163 }
164 fd = file_getfd(fp);
165
166 tiu = kmem_zalloc(sizeof (*tiu), KM_SLEEP);
167 rc = t_getinfo(fd, &tiu->tp_info);
168 if (rc < 0) {
169 rc = t_errno;
170 cmn_err(CE_NOTE, "t_kopen: t_getinfo terr=%d", rc);
171 kmem_free(tiu, sizeof (*tiu));
172 if (madefp) {
173 file_releasef(fd);
174 (void) t_close(fd);
175 }
176 return (tlitosyserr(rc));
177 }
178
179 tiu->fp = fp;
180 tiu->flags = madefp ? MADE_FP : 0;
181 *tiptr = tiu;
182
183 return (0);
184 }
185
186 /* ARGSUSED */
187 int
t_kclose(TIUSER * tiptr,int callclosef)188 t_kclose(TIUSER *tiptr, int callclosef)
189 {
190 file_t *fp;
191
192 fp = (tiptr->flags & MADE_FP) ? tiptr->fp : NULL;
193
194 kmem_free(tiptr, TIUSERSZ);
195
196 if (fp != NULL) {
197 int fd = file_getfd(fp);
198 file_releasef(fd);
199 (void) t_close(fd);
200 }
201
202 return (0);
203 }
204
205 int
t_kbind(TIUSER * tiptr,struct t_bind * req,struct t_bind * ret)206 t_kbind(TIUSER *tiptr, struct t_bind *req, struct t_bind *ret)
207 {
208 file_t *fp = tiptr->fp;
209 int fd = file_getfd(fp);
210 int rc;
211
212 if (t_bind(fd, req, ret) < 0) {
213 rc = t_errno;
214 cmn_err(CE_NOTE, "t_kbind: t_bind terr=%d", rc);
215 return (tlitosyserr(rc));
216 }
217 return (0);
218 }
219
220 int
t_kunbind(TIUSER * tiptr)221 t_kunbind(TIUSER *tiptr)
222 {
223 file_t *fp = tiptr->fp;
224 int fd = file_getfd(fp);
225 int rc;
226
227 if (t_unbind(fd) < 0) {
228 rc = t_errno;
229 cmn_err(CE_NOTE, "t_kunbind: t_unbind terr=%d", rc);
230 return (tlitosyserr(rc));
231 }
232 return (0);
233 }
234
235 int
t_kconnect(TIUSER * tiptr,struct t_call * sndcall,struct t_call * rcvcall)236 t_kconnect(TIUSER *tiptr, struct t_call *sndcall, struct t_call *rcvcall)
237 {
238 file_t *fp = tiptr->fp;
239 int fd = file_getfd(fp);
240 int rc;
241
242 if (t_connect(fd, sndcall, rcvcall) < 0) {
243 rc = t_errno;
244 cmn_err(CE_NOTE, "t_kconnect: t_connect terr=%d", rc);
245 if (rc == TLOOK) {
246 /* Probably got a RST. */
247 rc = ECONNREFUSED;
248 } else {
249 rc = tlitosyserr(rc);
250 }
251 return (rc);
252 }
253 return (0);
254 }
255
256 int
t_koptmgmt(TIUSER * tiptr,struct t_optmgmt * req,struct t_optmgmt * ret)257 t_koptmgmt(TIUSER *tiptr, struct t_optmgmt *req, struct t_optmgmt *ret)
258 {
259 file_t *fp = tiptr->fp;
260 int fd = file_getfd(fp);
261 int rc;
262
263 if (t_optmgmt(fd, req, ret) < 0) {
264 rc = t_errno;
265 cmn_err(CE_NOTE, "t_koptmgmt: t_optmgmt terr=%d", rc);
266 return (tlitosyserr(rc));
267 }
268 return (0);
269 }
270
271 /*
272 * Poll for an input event.
273 *
274 * timo is measured in ticks
275 */
276 int
t_kspoll(TIUSER * tiptr,int timo,int waitflg,int * events)277 t_kspoll(TIUSER *tiptr, int timo, int waitflg, int *events)
278 {
279 struct pollfd pfds[1];
280 file_t *fp = tiptr->fp;
281 int fd = file_getfd(fp);
282 clock_t timout; /* milliseconds */
283 int n;
284
285 if (events == NULL || ((waitflg & READWAIT) == 0))
286 return (EINVAL);
287
288 /* Convert from ticks to milliseconds */
289 if (timo < 0)
290 timout = -1;
291 else
292 timout = TICK_TO_MSEC(timo);
293
294 pfds[0].fd = fd;
295 pfds[0].events = POLLIN;
296 pfds[0].revents = 0;
297
298 errno = 0;
299 n = poll(pfds, 1, timout);
300 if (n < 0)
301 return (errno);
302 if (n == 0)
303 return (ETIME);
304 *events = pfds[0].revents;
305 return (0);
306 }
307
308 /*
309 * Send the message, return zero or errno.
310 * Always free's the message, even on error.
311 */
312 int
tli_send(TIUSER * tiptr,mblk_t * bp,int fmode)313 tli_send(TIUSER *tiptr, mblk_t *bp, int fmode)
314 {
315 struct strbuf ctlbuf;
316 struct strbuf databuf;
317 mblk_t *m;
318 int flg, n, rc;
319 file_t *fp = tiptr->fp;
320 int fd = file_getfd(fp);
321
322 if (bp == NULL)
323 return (0);
324
325 switch (bp->b_datap->db_type) {
326 case M_DATA:
327 for (m = bp; m != NULL; m = m->b_cont) {
328 n = MBLKL(m);
329 flg = (m->b_cont != NULL) ? T_MORE : 0;
330 rc = t_snd(fd, (void *) m->b_rptr, n, flg);
331 if (rc != n) {
332 rc = EIO;
333 goto out;
334 }
335 }
336 rc = 0;
337 break;
338
339 /*
340 * May get M_PROTO/T_DISCON_REQ from nb_snddis()
341 */
342 case M_PROTO:
343 case M_PCPROTO:
344 ctlbuf.len = MBLKL(bp);
345 ctlbuf.maxlen = MBLKL(bp);
346 ctlbuf.buf = (char *)bp->b_rptr;
347 if (bp->b_cont == NULL) {
348 bzero(&databuf, sizeof (databuf));
349 } else {
350 m = bp->b_cont;
351 databuf.len = MBLKL(m);
352 databuf.maxlen = MBLKL(m);
353 databuf.buf = (char *)m->b_rptr;
354 }
355 if (putmsg(fd, &ctlbuf, &databuf, 0) < 0) {
356 rc = errno;
357 cmn_err(CE_NOTE, "tli_send: putmsg err=%d", rc);
358 } else {
359 rc = 0;
360 }
361 break;
362
363 default:
364 rc = EIO;
365 break;
366 }
367
368 out:
369 freemsg(bp);
370 return (rc);
371 }
372
373 int
tli_recv(TIUSER * tiptr,mblk_t ** bp,int fmode)374 tli_recv(TIUSER *tiptr, mblk_t **bp, int fmode)
375 {
376 mblk_t *mtop = NULL;
377 mblk_t *m;
378 file_t *fp = tiptr->fp;
379 int fd = file_getfd(fp);
380 int error;
381 int flags;
382 int nread;
383 int n;
384
385 /*
386 * Get an mblk for the data
387 */
388 nread = FKTLI_RCV_SZ;
389 m = allocb_wait(nread, 0, 0, &error);
390 ASSERT(m != NULL);
391
392 if (mtop == NULL)
393 mtop = m;
394
395 again:
396 flags = 0;
397 n = t_rcv(fd, (void *) m->b_rptr, nread, &flags);
398 if (n < 0) {
399 n = t_errno;
400 cmn_err(CE_NOTE, "tli_recv: t_rcv terr=%d", n);
401 error = tlitosyserr(n);
402 goto errout;
403 }
404 if (n == 0) {
405 error = ENOTCONN;
406 goto errout;
407 }
408 ASSERT(n > 0 && n <= nread);
409 m->b_wptr = m->b_rptr + n;
410
411 if (flags & T_MORE) {
412 mblk_t *mtail = m;
413 m = allocb_wait(nread, 0, 0, &error);
414 ASSERT(m != NULL);
415 mtail->b_cont = m;
416 goto again;
417 }
418
419 *bp = mtop;
420 return (0);
421
422 errout:
423 if (m == mtop) {
424 freemsg(mtop);
425 return (error);
426 }
427
428 /* got some data, so return it. */
429 return (0);
430 }
431