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