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