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