xref: /illumos-gate/usr/src/lib/smbclnt/libfknsmb/common/fake_ktli.c (revision 8119dad84d6416f13557b0ba8e2aaf9064cbcfd3)
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
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
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
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
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
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
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
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
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
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
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