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