16007Sthurlow /*
26007Sthurlow * Copyright (c) 2000, Boris Popov
36007Sthurlow * All rights reserved.
46007Sthurlow *
56007Sthurlow * Redistribution and use in source and binary forms, with or without
66007Sthurlow * modification, are permitted provided that the following conditions
76007Sthurlow * are met:
86007Sthurlow * 1. Redistributions of source code must retain the above copyright
96007Sthurlow * notice, this list of conditions and the following disclaimer.
106007Sthurlow * 2. Redistributions in binary form must reproduce the above copyright
116007Sthurlow * notice, this list of conditions and the following disclaimer in the
126007Sthurlow * documentation and/or other materials provided with the distribution.
136007Sthurlow * 3. All advertising materials mentioning features or use of this software
146007Sthurlow * must display the following acknowledgement:
156007Sthurlow * This product includes software developed by Boris Popov.
166007Sthurlow * 4. Neither the name of the author nor the names of any co-contributors
176007Sthurlow * may be used to endorse or promote products derived from this software
186007Sthurlow * without specific prior written permission.
196007Sthurlow *
206007Sthurlow * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
216007Sthurlow * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226007Sthurlow * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236007Sthurlow * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
246007Sthurlow * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256007Sthurlow * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266007Sthurlow * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276007Sthurlow * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286007Sthurlow * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296007Sthurlow * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306007Sthurlow * SUCH DAMAGE.
316007Sthurlow *
326007Sthurlow * $Id: file.c,v 1.4 2004/12/13 00:25:21 lindak Exp $
336007Sthurlow */
346007Sthurlow
358271SGordon.Ross@Sun.COM /*
3610023SGordon.Ross@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
378271SGordon.Ross@Sun.COM * Use is subject to license terms.
388271SGordon.Ross@Sun.COM */
396007Sthurlow
406007Sthurlow #include <sys/param.h>
416007Sthurlow #include <sys/ioctl.h>
426007Sthurlow #include <sys/time.h>
436007Sthurlow #include <sys/mount.h>
446007Sthurlow #include <fcntl.h>
456007Sthurlow #include <ctype.h>
466007Sthurlow #include <errno.h>
476007Sthurlow #include <stdio.h>
486007Sthurlow #include <string.h>
496007Sthurlow #include <strings.h>
506007Sthurlow #include <stdlib.h>
516007Sthurlow #include <pwd.h>
526007Sthurlow #include <grp.h>
536007Sthurlow #include <unistd.h>
548271SGordon.Ross@Sun.COM #include <libintl.h>
556007Sthurlow
566007Sthurlow #include <sys/types.h>
578271SGordon.Ross@Sun.COM #include <sys/file.h>
586007Sthurlow
5910023SGordon.Ross@Sun.COM #include <netsmb/smb.h>
606007Sthurlow #include <netsmb/smb_lib.h>
616007Sthurlow
628271SGordon.Ross@Sun.COM #include "private.h"
638271SGordon.Ross@Sun.COM
646007Sthurlow int
smb_fh_close(struct smb_ctx * ctx,int fh)6510023SGordon.Ross@Sun.COM smb_fh_close(struct smb_ctx *ctx, int fh)
668271SGordon.Ross@Sun.COM {
678271SGordon.Ross@Sun.COM struct smb_rq *rqp;
688271SGordon.Ross@Sun.COM struct mbdata *mbp;
6910023SGordon.Ross@Sun.COM int error;
708271SGordon.Ross@Sun.COM
7110023SGordon.Ross@Sun.COM error = smb_rq_init(ctx, SMB_COM_CLOSE, &rqp);
7210023SGordon.Ross@Sun.COM if (error != 0)
7310023SGordon.Ross@Sun.COM return (error);
748271SGordon.Ross@Sun.COM mbp = smb_rq_getrequest(rqp);
7510023SGordon.Ross@Sun.COM smb_rq_wstart(rqp);
7610023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, (uint16_t)fh);
778271SGordon.Ross@Sun.COM mb_put_uint32le(mbp, 0); /* time stamp */
788271SGordon.Ross@Sun.COM smb_rq_wend(rqp);
7910023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, 0); /* byte count */
8010023SGordon.Ross@Sun.COM
8110023SGordon.Ross@Sun.COM error = smb_rq_simple(rqp);
828271SGordon.Ross@Sun.COM smb_rq_done(rqp);
838271SGordon.Ross@Sun.COM
8410023SGordon.Ross@Sun.COM return (error);
858271SGordon.Ross@Sun.COM }
868271SGordon.Ross@Sun.COM
878271SGordon.Ross@Sun.COM int
smb_fh_ntcreate(struct smb_ctx * ctx,char * path,int flags,int req_acc,int efattr,int share_acc,int open_disp,int create_opts,int impersonation,int * fhp,uint32_t * action_taken)888271SGordon.Ross@Sun.COM smb_fh_ntcreate(
898271SGordon.Ross@Sun.COM struct smb_ctx *ctx, char *path,
908271SGordon.Ross@Sun.COM int flags, int req_acc, int efattr,
918271SGordon.Ross@Sun.COM int share_acc, int open_disp,
928271SGordon.Ross@Sun.COM int create_opts, int impersonation,
9310023SGordon.Ross@Sun.COM int *fhp, uint32_t *action_taken)
948271SGordon.Ross@Sun.COM {
958271SGordon.Ross@Sun.COM struct smb_rq *rqp;
968271SGordon.Ross@Sun.COM struct mbdata *mbp;
9710023SGordon.Ross@Sun.COM char *pathsizep;
9810023SGordon.Ross@Sun.COM int pathstart, pathsize;
9910023SGordon.Ross@Sun.COM int error, flags2, uc;
10010023SGordon.Ross@Sun.COM uint16_t fh;
1018271SGordon.Ross@Sun.COM uint8_t wc;
1028271SGordon.Ross@Sun.COM
1038271SGordon.Ross@Sun.COM flags2 = smb_ctx_flags2(ctx);
1048271SGordon.Ross@Sun.COM if (flags2 == -1)
1058271SGordon.Ross@Sun.COM return (EIO);
10610023SGordon.Ross@Sun.COM uc = flags2 & SMB_FLAGS2_UNICODE;
1078271SGordon.Ross@Sun.COM
10810023SGordon.Ross@Sun.COM error = smb_rq_init(ctx, SMB_COM_NT_CREATE_ANDX, &rqp);
1098271SGordon.Ross@Sun.COM if (error != 0)
1108271SGordon.Ross@Sun.COM return (error);
1118271SGordon.Ross@Sun.COM
1128271SGordon.Ross@Sun.COM mbp = smb_rq_getrequest(rqp);
11310023SGordon.Ross@Sun.COM smb_rq_wstart(rqp);
11410023SGordon.Ross@Sun.COM mb_put_uint16le(mbp, 0xff); /* secondary command */
1158271SGordon.Ross@Sun.COM mb_put_uint16le(mbp, 0); /* offset to next command (none) */
11610023SGordon.Ross@Sun.COM mb_put_uint8(mbp, 0); /* MBZ (pad?) */
117*11332SGordon.Ross@Sun.COM (void) mb_fit(mbp, 2, &pathsizep); /* path size - fill in below */
11810023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, flags); /* create flags (oplock) */
1198271SGordon.Ross@Sun.COM mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */
1208271SGordon.Ross@Sun.COM mb_put_uint32le(mbp, req_acc);
1218271SGordon.Ross@Sun.COM mb_put_uint64le(mbp, 0); /* initial alloc. size */
1228271SGordon.Ross@Sun.COM mb_put_uint32le(mbp, efattr); /* ext. file attributes */
1238271SGordon.Ross@Sun.COM mb_put_uint32le(mbp, share_acc); /* share access mode */
1248271SGordon.Ross@Sun.COM mb_put_uint32le(mbp, open_disp); /* open disposition */
1258271SGordon.Ross@Sun.COM mb_put_uint32le(mbp, create_opts); /* create_options */
12610023SGordon.Ross@Sun.COM mb_put_uint32le(mbp, impersonation);
1278271SGordon.Ross@Sun.COM mb_put_uint8(mbp, 0); /* security flags (?) */
1288271SGordon.Ross@Sun.COM smb_rq_wend(rqp);
12910023SGordon.Ross@Sun.COM smb_rq_bstart(rqp);
13010023SGordon.Ross@Sun.COM if (uc) {
13110023SGordon.Ross@Sun.COM /*
13210023SGordon.Ross@Sun.COM * We're about to put a unicode string. We know
13310023SGordon.Ross@Sun.COM * we're misaligned at this point, and need to
13410023SGordon.Ross@Sun.COM * save the mb_count at the start of the string,
13510023SGordon.Ross@Sun.COM * not at the alignment padding placed before it.
13610023SGordon.Ross@Sun.COM * So add the algnment padding by hand here.
13710023SGordon.Ross@Sun.COM */
13810023SGordon.Ross@Sun.COM mb_put_uint8(mbp, 0);
13910023SGordon.Ross@Sun.COM }
14010023SGordon.Ross@Sun.COM pathstart = mbp->mb_count;
141*11332SGordon.Ross@Sun.COM mb_put_string(mbp, path, uc);
14210023SGordon.Ross@Sun.COM smb_rq_bend(rqp);
1438271SGordon.Ross@Sun.COM
14410023SGordon.Ross@Sun.COM /* Now go back and fill in pathsizep */
14510023SGordon.Ross@Sun.COM pathsize = mbp->mb_count - pathstart;
14610023SGordon.Ross@Sun.COM pathsizep[0] = pathsize & 0xFF;
14710023SGordon.Ross@Sun.COM pathsizep[1] = (pathsize >> 8);
1488271SGordon.Ross@Sun.COM
1498271SGordon.Ross@Sun.COM error = smb_rq_simple(rqp);
1508271SGordon.Ross@Sun.COM if (error)
1518271SGordon.Ross@Sun.COM goto out;
1528271SGordon.Ross@Sun.COM
1538271SGordon.Ross@Sun.COM mbp = smb_rq_getreply(rqp);
1548271SGordon.Ross@Sun.COM /*
1558271SGordon.Ross@Sun.COM * spec says 26 for word count, but 34 words are defined
1568271SGordon.Ross@Sun.COM * and observed from win2000
1578271SGordon.Ross@Sun.COM */
158*11332SGordon.Ross@Sun.COM error = md_get_uint8(mbp, &wc);
15910023SGordon.Ross@Sun.COM if (error || wc < 26) {
1608271SGordon.Ross@Sun.COM smb_error(dgettext(TEXT_DOMAIN,
1618271SGordon.Ross@Sun.COM "%s: open failed, bad word count"), 0, path);
1628271SGordon.Ross@Sun.COM error = EBADRPC;
1638271SGordon.Ross@Sun.COM goto out;
1648271SGordon.Ross@Sun.COM }
165*11332SGordon.Ross@Sun.COM md_get_uint8(mbp, NULL); /* secondary cmd */
166*11332SGordon.Ross@Sun.COM md_get_uint8(mbp, NULL); /* mbz */
167*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, NULL); /* andxoffset */
168*11332SGordon.Ross@Sun.COM md_get_uint8(mbp, NULL); /* oplock lvl granted */
169*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, &fh); /* FID */
170*11332SGordon.Ross@Sun.COM md_get_uint32le(mbp, action_taken);
1718271SGordon.Ross@Sun.COM #if 0 /* skip decoding the rest */
172*11332SGordon.Ross@Sun.COM md_get_uint64le(mbp, NULL); /* creation time */
173*11332SGordon.Ross@Sun.COM md_get_uint64le(mbp, NULL); /* access time */
174*11332SGordon.Ross@Sun.COM md_get_uint64le(mbp, NULL); /* write time */
175*11332SGordon.Ross@Sun.COM md_get_uint64le(mbp, NULL); /* change time */
176*11332SGordon.Ross@Sun.COM md_get_uint32le(mbp, NULL); /* attributes */
177*11332SGordon.Ross@Sun.COM md_get_uint64le(mbp, NULL); /* allocation size */
178*11332SGordon.Ross@Sun.COM md_get_uint64le(mbp, NULL); /* EOF */
179*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, NULL); /* file type */
180*11332SGordon.Ross@Sun.COM md_get_uint16le(mbp, NULL); /* device state */
181*11332SGordon.Ross@Sun.COM md_get_uint8(mbp, NULL); /* directory (boolean) */
18210023SGordon.Ross@Sun.COM #endif
18310023SGordon.Ross@Sun.COM
18410023SGordon.Ross@Sun.COM /* success! */
18510023SGordon.Ross@Sun.COM *fhp = fh;
18610023SGordon.Ross@Sun.COM error = 0;
1878271SGordon.Ross@Sun.COM
1888271SGordon.Ross@Sun.COM out:
1898271SGordon.Ross@Sun.COM smb_rq_done(rqp);
1908271SGordon.Ross@Sun.COM
19110023SGordon.Ross@Sun.COM return (error);
1928271SGordon.Ross@Sun.COM }
1938271SGordon.Ross@Sun.COM
1948271SGordon.Ross@Sun.COM /*
1958271SGordon.Ross@Sun.COM * Conveinence wrapper for smb_fh_ntcreate
1968271SGordon.Ross@Sun.COM * Converts Unix-style open call to NTCreate.
1978271SGordon.Ross@Sun.COM */
1988271SGordon.Ross@Sun.COM int
smb_fh_open(struct smb_ctx * ctx,const char * path,int oflag,int * fhp)19910023SGordon.Ross@Sun.COM smb_fh_open(struct smb_ctx *ctx, const char *path, int oflag, int *fhp)
2008271SGordon.Ross@Sun.COM {
2018271SGordon.Ross@Sun.COM int error, mode, open_disp, req_acc, share_acc;
2028271SGordon.Ross@Sun.COM char *p, *ntpath = NULL;
2038271SGordon.Ross@Sun.COM
2048271SGordon.Ross@Sun.COM /*
2058271SGordon.Ross@Sun.COM * Map O_RDONLY, O_WRONLY, O_RDWR
2068271SGordon.Ross@Sun.COM * to FREAD, FWRITE
2078271SGordon.Ross@Sun.COM */
2088271SGordon.Ross@Sun.COM mode = (oflag & 3) + 1;
2098271SGordon.Ross@Sun.COM
2108271SGordon.Ross@Sun.COM /*
2118271SGordon.Ross@Sun.COM * Compute requested access, share access.
2128271SGordon.Ross@Sun.COM */
2138271SGordon.Ross@Sun.COM req_acc = (
2148271SGordon.Ross@Sun.COM STD_RIGHT_READ_CONTROL_ACCESS |
2158271SGordon.Ross@Sun.COM STD_RIGHT_SYNCHRONIZE_ACCESS);
2168271SGordon.Ross@Sun.COM share_acc = NTCREATEX_SHARE_ACCESS_NONE;
2178271SGordon.Ross@Sun.COM if (mode & FREAD) {
2188271SGordon.Ross@Sun.COM req_acc |= (
2198271SGordon.Ross@Sun.COM SA_RIGHT_FILE_READ_DATA |
2208271SGordon.Ross@Sun.COM SA_RIGHT_FILE_READ_EA |
2218271SGordon.Ross@Sun.COM SA_RIGHT_FILE_READ_ATTRIBUTES);
2228271SGordon.Ross@Sun.COM share_acc |= NTCREATEX_SHARE_ACCESS_READ;
2238271SGordon.Ross@Sun.COM }
2248271SGordon.Ross@Sun.COM if (mode & FWRITE) {
2258271SGordon.Ross@Sun.COM req_acc |= (
2268271SGordon.Ross@Sun.COM SA_RIGHT_FILE_WRITE_DATA |
2278271SGordon.Ross@Sun.COM SA_RIGHT_FILE_APPEND_DATA |
2288271SGordon.Ross@Sun.COM SA_RIGHT_FILE_WRITE_EA |
2298271SGordon.Ross@Sun.COM SA_RIGHT_FILE_WRITE_ATTRIBUTES);
2308271SGordon.Ross@Sun.COM share_acc |= NTCREATEX_SHARE_ACCESS_WRITE;
2318271SGordon.Ross@Sun.COM }
2328271SGordon.Ross@Sun.COM
2338271SGordon.Ross@Sun.COM /*
2348271SGordon.Ross@Sun.COM * Compute open disposition
2358271SGordon.Ross@Sun.COM */
2368271SGordon.Ross@Sun.COM if (oflag & FCREAT) {
2378271SGordon.Ross@Sun.COM /* Creat if necessary. */
2388271SGordon.Ross@Sun.COM if (oflag & FEXCL) {
2398271SGordon.Ross@Sun.COM /* exclusive */
2408271SGordon.Ross@Sun.COM open_disp = NTCREATEX_DISP_CREATE;
2418271SGordon.Ross@Sun.COM } else if (oflag & FTRUNC)
2428271SGordon.Ross@Sun.COM open_disp = NTCREATEX_DISP_OVERWRITE_IF;
2438271SGordon.Ross@Sun.COM else
2448271SGordon.Ross@Sun.COM open_disp = NTCREATEX_DISP_OPEN_IF;
2458271SGordon.Ross@Sun.COM } else {
2468271SGordon.Ross@Sun.COM /* Not creating. */
2478271SGordon.Ross@Sun.COM if (oflag & FTRUNC)
2488271SGordon.Ross@Sun.COM open_disp = NTCREATEX_DISP_OVERWRITE;
2498271SGordon.Ross@Sun.COM else
2508271SGordon.Ross@Sun.COM open_disp = NTCREATEX_DISP_OPEN;
2518271SGordon.Ross@Sun.COM }
2528271SGordon.Ross@Sun.COM
2538271SGordon.Ross@Sun.COM /*
2548271SGordon.Ross@Sun.COM * Convert Unix path to NT (backslashes)
2558271SGordon.Ross@Sun.COM */
2568271SGordon.Ross@Sun.COM ntpath = strdup(path);
2578271SGordon.Ross@Sun.COM if (ntpath == NULL)
2588271SGordon.Ross@Sun.COM return (ENOMEM);
2598271SGordon.Ross@Sun.COM for (p = ntpath; *p; p++)
2608271SGordon.Ross@Sun.COM if (*p == '/')
2618271SGordon.Ross@Sun.COM *p = '\\';
2628271SGordon.Ross@Sun.COM
2638271SGordon.Ross@Sun.COM error = smb_fh_ntcreate(ctx, ntpath, 0, /* flags */
2648271SGordon.Ross@Sun.COM req_acc, SMB_EFA_NORMAL, share_acc, open_disp,
2658271SGordon.Ross@Sun.COM NTCREATEX_OPTIONS_NON_DIRECTORY_FILE,
2668271SGordon.Ross@Sun.COM NTCREATEX_IMPERSONATION_IMPERSONATION,
2678271SGordon.Ross@Sun.COM fhp, NULL);
2688271SGordon.Ross@Sun.COM free(ntpath);
2698271SGordon.Ross@Sun.COM
2708271SGordon.Ross@Sun.COM return (error);
2718271SGordon.Ross@Sun.COM }
2728271SGordon.Ross@Sun.COM
2738271SGordon.Ross@Sun.COM int
smb_fh_read(struct smb_ctx * ctx,int fh,off_t offset,size_t count,char * dst)27410023SGordon.Ross@Sun.COM smb_fh_read(struct smb_ctx *ctx, int fh, off_t offset, size_t count,
2758271SGordon.Ross@Sun.COM char *dst)
2766007Sthurlow {
2776007Sthurlow struct smbioc_rw rwrq;
2786007Sthurlow
2796007Sthurlow bzero(&rwrq, sizeof (rwrq));
2806007Sthurlow rwrq.ioc_fh = fh;
2816007Sthurlow rwrq.ioc_base = dst;
2826007Sthurlow rwrq.ioc_cnt = count;
2836007Sthurlow rwrq.ioc_offset = offset;
28410023SGordon.Ross@Sun.COM if (ioctl(ctx->ct_dev_fd, SMBIOC_READ, &rwrq) == -1) {
2856007Sthurlow return (-1);
2866007Sthurlow }
2876007Sthurlow return (rwrq.ioc_cnt);
2886007Sthurlow }
2896007Sthurlow
2906007Sthurlow int
smb_fh_write(struct smb_ctx * ctx,int fh,off_t offset,size_t count,const char * src)29110023SGordon.Ross@Sun.COM smb_fh_write(struct smb_ctx *ctx, int fh, off_t offset, size_t count,
2926007Sthurlow const char *src)
2936007Sthurlow {
2946007Sthurlow struct smbioc_rw rwrq;
2956007Sthurlow
2966007Sthurlow bzero(&rwrq, sizeof (rwrq));
2976007Sthurlow rwrq.ioc_fh = fh;
2986007Sthurlow rwrq.ioc_base = (char *)src;
2996007Sthurlow rwrq.ioc_cnt = count;
3006007Sthurlow rwrq.ioc_offset = offset;
30110023SGordon.Ross@Sun.COM if (ioctl(ctx->ct_dev_fd, SMBIOC_WRITE, &rwrq) == -1) {
3026007Sthurlow return (-1);
3036007Sthurlow }
3046007Sthurlow return (rwrq.ioc_cnt);
3056007Sthurlow }
3068271SGordon.Ross@Sun.COM
3078271SGordon.Ross@Sun.COM /*
3088271SGordon.Ross@Sun.COM * Do a TRANSACT_NAMED_PIPE, which is basically just a
3098271SGordon.Ross@Sun.COM * pipe write and pipe read, all in one round trip.
3108271SGordon.Ross@Sun.COM *
3118271SGordon.Ross@Sun.COM * tdlen, tdata describe the data to send.
3128271SGordon.Ross@Sun.COM * rdlen, rdata on input describe the receive buffer,
3138271SGordon.Ross@Sun.COM * and on output *rdlen is the received length.
3148271SGordon.Ross@Sun.COM */
3158271SGordon.Ross@Sun.COM int
smb_fh_xactnp(struct smb_ctx * ctx,int fh,int tdlen,const char * tdata,int * rdlen,char * rdata,int * more)31610023SGordon.Ross@Sun.COM smb_fh_xactnp(struct smb_ctx *ctx, int fh,
3178271SGordon.Ross@Sun.COM int tdlen, const char *tdata, /* transmit */
3188271SGordon.Ross@Sun.COM int *rdlen, char *rdata, /* receive */
3198271SGordon.Ross@Sun.COM int *more)
3208271SGordon.Ross@Sun.COM {
3218271SGordon.Ross@Sun.COM int err, rparamcnt;
3228271SGordon.Ross@Sun.COM uint16_t setup[2];
3238271SGordon.Ross@Sun.COM
3248271SGordon.Ross@Sun.COM setup[0] = TRANS_TRANSACT_NAMED_PIPE;
3258271SGordon.Ross@Sun.COM setup[1] = fh;
3268271SGordon.Ross@Sun.COM rparamcnt = 0;
3278271SGordon.Ross@Sun.COM
3288271SGordon.Ross@Sun.COM err = smb_t2_request(ctx, 2, setup, "\\PIPE\\",
3298271SGordon.Ross@Sun.COM 0, NULL, /* TX paramcnt, params */
3308271SGordon.Ross@Sun.COM tdlen, (void *)tdata,
3318271SGordon.Ross@Sun.COM &rparamcnt, NULL, /* no RX params */
3328271SGordon.Ross@Sun.COM rdlen, rdata, more);
3338271SGordon.Ross@Sun.COM
3348271SGordon.Ross@Sun.COM if (err)
3358271SGordon.Ross@Sun.COM *rdlen = 0;
3368271SGordon.Ross@Sun.COM
3378271SGordon.Ross@Sun.COM return (err);
3388271SGordon.Ross@Sun.COM }
339