nfs_srvsubs.c revision 100134
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * This code is derived from software contributed to Berkeley by
61541Srgrimes * Rick Macklem at The University of Guelph.
71541Srgrimes *
81541Srgrimes * Redistribution and use in source and binary forms, with or without
91541Srgrimes * modification, are permitted provided that the following conditions
101541Srgrimes * are met:
111541Srgrimes * 1. Redistributions of source code must retain the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer.
131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer in the
151541Srgrimes *    documentation and/or other materials provided with the distribution.
161541Srgrimes * 3. All advertising materials mentioning features or use of this software
171541Srgrimes *    must display the following acknowledgement:
181541Srgrimes *	This product includes software developed by the University of
191541Srgrimes *	California, Berkeley and its contributors.
201541Srgrimes * 4. Neither the name of the University nor the names of its contributors
211541Srgrimes *    may be used to endorse or promote products derived from this software
221541Srgrimes *    without specific prior written permission.
231541Srgrimes *
241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341541Srgrimes * SUCH DAMAGE.
351541Srgrimes *
3636503Speter *	@(#)nfs_subs.c  8.8 (Berkeley) 5/22/95
3750477Speter * $FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 100134 2002-07-15 19:40:23Z alfred $
381541Srgrimes */
391541Srgrimes
4083651Speter#include <sys/cdefs.h>
4183651Speter__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 100134 2002-07-15 19:40:23Z alfred $");
4283651Speter
431541Srgrimes/*
441541Srgrimes * These functions support the macros and help fiddle mbuf chains for
451541Srgrimes * the nfs op functions. They do things like create the rpc header and
461541Srgrimes * copy data between mbuf chains and uio lists.
471541Srgrimes */
4883651Speter
49100134Salfred#include "opt_inet6.h"
50100134Salfred
511541Srgrimes#include <sys/param.h>
5248274Speter#include <sys/systm.h>
5348274Speter#include <sys/kernel.h>
5460041Sphk#include <sys/bio.h>
5531886Sbde#include <sys/buf.h>
561541Srgrimes#include <sys/proc.h>
571541Srgrimes#include <sys/mount.h>
581541Srgrimes#include <sys/vnode.h>
591541Srgrimes#include <sys/namei.h>
601541Srgrimes#include <sys/mbuf.h>
611541Srgrimes#include <sys/socket.h>
621541Srgrimes#include <sys/stat.h>
639336Sdfr#include <sys/malloc.h>
6483700Speter#include <sys/module.h>
652997Swollman#include <sys/sysent.h>
662997Swollman#include <sys/syscall.h>
6783651Speter#include <sys/sysproto.h>
681541Srgrimes
693305Sphk#include <vm/vm.h>
7012662Sdg#include <vm/vm_object.h>
7112662Sdg#include <vm/vm_extern.h>
7292783Sjeff#include <vm/uma.h>
733305Sphk
741541Srgrimes#include <nfs/rpcv2.h>
759336Sdfr#include <nfs/nfsproto.h>
7683651Speter#include <nfsserver/nfs.h>
771541Srgrimes#include <nfs/xdr_subs.h>
7883651Speter#include <nfsserver/nfsm_subs.h>
791541Srgrimes
801541Srgrimes#include <netinet/in.h>
811541Srgrimes
821541Srgrimes/*
831541Srgrimes * Data items converted to xdr at startup, since they are constant
841541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps
851541Srgrimes */
8689094Smsmithu_int32_t nfsrv_nfs_xdrneg1;
8789094Smsmithu_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply,
8889094Smsmith	nfsrv_rpc_msgdenied, nfsrv_rpc_autherr,
8989094Smsmith	nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted;
9089094Smsmithu_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
911541Srgrimes
921541Srgrimes/* And other global data */
9383651Speterstatic nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
9483651Speter				 NFNON, NFCHR, NFNON };
9583651Speter#define vtonfsv2_type(a)	txdr_unsigned(nfsv2_type[((int32_t)(a))])
9683651Speter#define vtonfsv3_mode(m)	txdr_unsigned((m) & ALLPERMS)
9712911Sphk
9889094Smsmithint nfsrv_ticks;
999336Sdfr
1009759Sbdestruct nfssvc_sockhead nfssvc_sockhead;
1019759Sbdeint nfssvc_sockhead_flag;
1029759Sbdestruct nfsd_head nfsd_head;
1039759Sbdeint nfsd_head_flag;
1049759Sbde
10538894Sbdestatic int nfs_prev_nfssvc_sy_narg;
10638894Sbdestatic sy_call_t *nfs_prev_nfssvc_sy_call;
10738894Sbde
1089336Sdfr/*
1099336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers.
1109336Sdfr */
11189094Smsmithint nfsrv_nfsv3_procid[NFS_NPROCS] = {
1129336Sdfr	NFSPROC_NULL,
1139336Sdfr	NFSPROC_GETATTR,
1149336Sdfr	NFSPROC_SETATTR,
1159336Sdfr	NFSPROC_NOOP,
1169336Sdfr	NFSPROC_LOOKUP,
1179336Sdfr	NFSPROC_READLINK,
1189336Sdfr	NFSPROC_READ,
1199336Sdfr	NFSPROC_NOOP,
1209336Sdfr	NFSPROC_WRITE,
1219336Sdfr	NFSPROC_CREATE,
1229336Sdfr	NFSPROC_REMOVE,
1239336Sdfr	NFSPROC_RENAME,
1249336Sdfr	NFSPROC_LINK,
1259336Sdfr	NFSPROC_SYMLINK,
1269336Sdfr	NFSPROC_MKDIR,
1279336Sdfr	NFSPROC_RMDIR,
1289336Sdfr	NFSPROC_READDIR,
1299336Sdfr	NFSPROC_FSSTAT,
1309336Sdfr	NFSPROC_NOOP,
1319336Sdfr	NFSPROC_NOOP,
1329336Sdfr	NFSPROC_NOOP,
1339336Sdfr	NFSPROC_NOOP,
1349336Sdfr	NFSPROC_NOOP,
1359336Sdfr};
1369336Sdfr
1379336Sdfr/*
1389336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers
1399336Sdfr */
14083651Speterint nfsrvv2_procid[NFS_NPROCS] = {
1419336Sdfr	NFSV2PROC_NULL,
1429336Sdfr	NFSV2PROC_GETATTR,
1439336Sdfr	NFSV2PROC_SETATTR,
1449336Sdfr	NFSV2PROC_LOOKUP,
1459336Sdfr	NFSV2PROC_NOOP,
1469336Sdfr	NFSV2PROC_READLINK,
1479336Sdfr	NFSV2PROC_READ,
1489336Sdfr	NFSV2PROC_WRITE,
1499336Sdfr	NFSV2PROC_CREATE,
1509336Sdfr	NFSV2PROC_MKDIR,
1519336Sdfr	NFSV2PROC_SYMLINK,
1529336Sdfr	NFSV2PROC_CREATE,
1539336Sdfr	NFSV2PROC_REMOVE,
1549336Sdfr	NFSV2PROC_RMDIR,
1559336Sdfr	NFSV2PROC_RENAME,
1569336Sdfr	NFSV2PROC_LINK,
1579336Sdfr	NFSV2PROC_READDIR,
1589336Sdfr	NFSV2PROC_NOOP,
1599336Sdfr	NFSV2PROC_STATFS,
1609336Sdfr	NFSV2PROC_NOOP,
1619336Sdfr	NFSV2PROC_NOOP,
1629336Sdfr	NFSV2PROC_NOOP,
1639336Sdfr	NFSV2PROC_NOOP,
1649336Sdfr};
1659336Sdfr
1669336Sdfr/*
1679336Sdfr * Maps errno values to nfs error numbers.
1689336Sdfr * Use NFSERR_IO as the catch all for ones not specifically defined in
1699336Sdfr * RFC 1094.
1709336Sdfr */
1719336Sdfrstatic u_char nfsrv_v2errmap[ELAST] = {
1729336Sdfr  NFSERR_PERM,	NFSERR_NOENT,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1739336Sdfr  NFSERR_NXIO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1749336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_ACCES,	NFSERR_IO,	NFSERR_IO,
1759336Sdfr  NFSERR_IO,	NFSERR_EXIST,	NFSERR_IO,	NFSERR_NODEV,	NFSERR_NOTDIR,
1769336Sdfr  NFSERR_ISDIR,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1779336Sdfr  NFSERR_IO,	NFSERR_FBIG,	NFSERR_NOSPC,	NFSERR_IO,	NFSERR_ROFS,
1789336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1799336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1809336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1819336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1829336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1839336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1849336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_NAMETOL,	NFSERR_IO,	NFSERR_IO,
1859336Sdfr  NFSERR_NOTEMPTY, NFSERR_IO,	NFSERR_IO,	NFSERR_DQUOT,	NFSERR_STALE,
1869336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
1879336Sdfr  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
18841796Sdt  NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,	NFSERR_IO,
18941796Sdt  NFSERR_IO /* << Last is 86 */
1909336Sdfr};
1919336Sdfr
1929336Sdfr/*
1939336Sdfr * Maps errno values to nfs error numbers.
1949336Sdfr * Although it is not obvious whether or not NFS clients really care if
1959336Sdfr * a returned error value is in the specified list for the procedure, the
1969336Sdfr * safest thing to do is filter them appropriately. For Version 2, the
1979336Sdfr * X/Open XNFS document is the only specification that defines error values
1989336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs),
1999336Sdfr * so I have decided to not do this for Version 2.
2009336Sdfr * The first entry is the default error return and the rest are the valid
2019336Sdfr * errors for that RPC in increasing numeric order.
2029336Sdfr */
2039336Sdfrstatic short nfsv3err_null[] = {
2049336Sdfr	0,
2059336Sdfr	0,
2069336Sdfr};
2079336Sdfr
2089336Sdfrstatic short nfsv3err_getattr[] = {
2099336Sdfr	NFSERR_IO,
2109336Sdfr	NFSERR_IO,
2119336Sdfr	NFSERR_STALE,
2129336Sdfr	NFSERR_BADHANDLE,
2139336Sdfr	NFSERR_SERVERFAULT,
2149336Sdfr	0,
2159336Sdfr};
2169336Sdfr
2179336Sdfrstatic short nfsv3err_setattr[] = {
2189336Sdfr	NFSERR_IO,
2199336Sdfr	NFSERR_PERM,
2209336Sdfr	NFSERR_IO,
2219336Sdfr	NFSERR_ACCES,
2229336Sdfr	NFSERR_INVAL,
2239336Sdfr	NFSERR_NOSPC,
2249336Sdfr	NFSERR_ROFS,
2259336Sdfr	NFSERR_DQUOT,
2269336Sdfr	NFSERR_STALE,
2279336Sdfr	NFSERR_BADHANDLE,
2289336Sdfr	NFSERR_NOT_SYNC,
2299336Sdfr	NFSERR_SERVERFAULT,
2309336Sdfr	0,
2319336Sdfr};
2329336Sdfr
2339336Sdfrstatic short nfsv3err_lookup[] = {
2349336Sdfr	NFSERR_IO,
2359336Sdfr	NFSERR_NOENT,
2369336Sdfr	NFSERR_IO,
2379336Sdfr	NFSERR_ACCES,
2389336Sdfr	NFSERR_NOTDIR,
2399336Sdfr	NFSERR_NAMETOL,
2409336Sdfr	NFSERR_STALE,
2419336Sdfr	NFSERR_BADHANDLE,
2429336Sdfr	NFSERR_SERVERFAULT,
2439336Sdfr	0,
2449336Sdfr};
2459336Sdfr
2469336Sdfrstatic short nfsv3err_access[] = {
2479336Sdfr	NFSERR_IO,
2489336Sdfr	NFSERR_IO,
2499336Sdfr	NFSERR_STALE,
2509336Sdfr	NFSERR_BADHANDLE,
2519336Sdfr	NFSERR_SERVERFAULT,
2529336Sdfr	0,
2539336Sdfr};
2549336Sdfr
2559336Sdfrstatic short nfsv3err_readlink[] = {
2569336Sdfr	NFSERR_IO,
2579336Sdfr	NFSERR_IO,
2589336Sdfr	NFSERR_ACCES,
2599336Sdfr	NFSERR_INVAL,
2609336Sdfr	NFSERR_STALE,
2619336Sdfr	NFSERR_BADHANDLE,
2629336Sdfr	NFSERR_NOTSUPP,
2639336Sdfr	NFSERR_SERVERFAULT,
2649336Sdfr	0,
2659336Sdfr};
2669336Sdfr
2679336Sdfrstatic short nfsv3err_read[] = {
2689336Sdfr	NFSERR_IO,
2699336Sdfr	NFSERR_IO,
2709336Sdfr	NFSERR_NXIO,
2719336Sdfr	NFSERR_ACCES,
2729336Sdfr	NFSERR_INVAL,
2739336Sdfr	NFSERR_STALE,
2749336Sdfr	NFSERR_BADHANDLE,
2759336Sdfr	NFSERR_SERVERFAULT,
2769336Sdfr	0,
2779336Sdfr};
2789336Sdfr
2799336Sdfrstatic short nfsv3err_write[] = {
2809336Sdfr	NFSERR_IO,
2819336Sdfr	NFSERR_IO,
2829336Sdfr	NFSERR_ACCES,
2839336Sdfr	NFSERR_INVAL,
2849336Sdfr	NFSERR_FBIG,
2859336Sdfr	NFSERR_NOSPC,
2869336Sdfr	NFSERR_ROFS,
2879336Sdfr	NFSERR_DQUOT,
2889336Sdfr	NFSERR_STALE,
2899336Sdfr	NFSERR_BADHANDLE,
2909336Sdfr	NFSERR_SERVERFAULT,
2919336Sdfr	0,
2929336Sdfr};
2939336Sdfr
2949336Sdfrstatic short nfsv3err_create[] = {
2959336Sdfr	NFSERR_IO,
2969336Sdfr	NFSERR_IO,
2979336Sdfr	NFSERR_ACCES,
2989336Sdfr	NFSERR_EXIST,
2999336Sdfr	NFSERR_NOTDIR,
3009336Sdfr	NFSERR_NOSPC,
3019336Sdfr	NFSERR_ROFS,
3029336Sdfr	NFSERR_NAMETOL,
3039336Sdfr	NFSERR_DQUOT,
3049336Sdfr	NFSERR_STALE,
3059336Sdfr	NFSERR_BADHANDLE,
3069336Sdfr	NFSERR_NOTSUPP,
3079336Sdfr	NFSERR_SERVERFAULT,
3089336Sdfr	0,
3099336Sdfr};
3109336Sdfr
3119336Sdfrstatic short nfsv3err_mkdir[] = {
3129336Sdfr	NFSERR_IO,
3139336Sdfr	NFSERR_IO,
3149336Sdfr	NFSERR_ACCES,
3159336Sdfr	NFSERR_EXIST,
3169336Sdfr	NFSERR_NOTDIR,
3179336Sdfr	NFSERR_NOSPC,
3189336Sdfr	NFSERR_ROFS,
3199336Sdfr	NFSERR_NAMETOL,
3209336Sdfr	NFSERR_DQUOT,
3219336Sdfr	NFSERR_STALE,
3229336Sdfr	NFSERR_BADHANDLE,
3239336Sdfr	NFSERR_NOTSUPP,
3249336Sdfr	NFSERR_SERVERFAULT,
3259336Sdfr	0,
3269336Sdfr};
3279336Sdfr
3289336Sdfrstatic short nfsv3err_symlink[] = {
3299336Sdfr	NFSERR_IO,
3309336Sdfr	NFSERR_IO,
3319336Sdfr	NFSERR_ACCES,
3329336Sdfr	NFSERR_EXIST,
3339336Sdfr	NFSERR_NOTDIR,
3349336Sdfr	NFSERR_NOSPC,
3359336Sdfr	NFSERR_ROFS,
3369336Sdfr	NFSERR_NAMETOL,
3379336Sdfr	NFSERR_DQUOT,
3389336Sdfr	NFSERR_STALE,
3399336Sdfr	NFSERR_BADHANDLE,
3409336Sdfr	NFSERR_NOTSUPP,
3419336Sdfr	NFSERR_SERVERFAULT,
3429336Sdfr	0,
3439336Sdfr};
3449336Sdfr
3459336Sdfrstatic short nfsv3err_mknod[] = {
3469336Sdfr	NFSERR_IO,
3479336Sdfr	NFSERR_IO,
3489336Sdfr	NFSERR_ACCES,
3499336Sdfr	NFSERR_EXIST,
3509336Sdfr	NFSERR_NOTDIR,
3519336Sdfr	NFSERR_NOSPC,
3529336Sdfr	NFSERR_ROFS,
3539336Sdfr	NFSERR_NAMETOL,
3549336Sdfr	NFSERR_DQUOT,
3559336Sdfr	NFSERR_STALE,
3569336Sdfr	NFSERR_BADHANDLE,
3579336Sdfr	NFSERR_NOTSUPP,
3589336Sdfr	NFSERR_SERVERFAULT,
3599336Sdfr	NFSERR_BADTYPE,
3609336Sdfr	0,
3619336Sdfr};
3629336Sdfr
3639336Sdfrstatic short nfsv3err_remove[] = {
3649336Sdfr	NFSERR_IO,
3659336Sdfr	NFSERR_NOENT,
3669336Sdfr	NFSERR_IO,
3679336Sdfr	NFSERR_ACCES,
3689336Sdfr	NFSERR_NOTDIR,
3699336Sdfr	NFSERR_ROFS,
3709336Sdfr	NFSERR_NAMETOL,
3719336Sdfr	NFSERR_STALE,
3729336Sdfr	NFSERR_BADHANDLE,
3739336Sdfr	NFSERR_SERVERFAULT,
3749336Sdfr	0,
3759336Sdfr};
3769336Sdfr
3779336Sdfrstatic short nfsv3err_rmdir[] = {
3789336Sdfr	NFSERR_IO,
3799336Sdfr	NFSERR_NOENT,
3809336Sdfr	NFSERR_IO,
3819336Sdfr	NFSERR_ACCES,
3829336Sdfr	NFSERR_EXIST,
3839336Sdfr	NFSERR_NOTDIR,
3849336Sdfr	NFSERR_INVAL,
3859336Sdfr	NFSERR_ROFS,
3869336Sdfr	NFSERR_NAMETOL,
3879336Sdfr	NFSERR_NOTEMPTY,
3889336Sdfr	NFSERR_STALE,
3899336Sdfr	NFSERR_BADHANDLE,
3909336Sdfr	NFSERR_NOTSUPP,
3919336Sdfr	NFSERR_SERVERFAULT,
3929336Sdfr	0,
3939336Sdfr};
3949336Sdfr
3959336Sdfrstatic short nfsv3err_rename[] = {
3969336Sdfr	NFSERR_IO,
3979336Sdfr	NFSERR_NOENT,
3989336Sdfr	NFSERR_IO,
3999336Sdfr	NFSERR_ACCES,
4009336Sdfr	NFSERR_EXIST,
4019336Sdfr	NFSERR_XDEV,
4029336Sdfr	NFSERR_NOTDIR,
4039336Sdfr	NFSERR_ISDIR,
4049336Sdfr	NFSERR_INVAL,
4059336Sdfr	NFSERR_NOSPC,
4069336Sdfr	NFSERR_ROFS,
4079336Sdfr	NFSERR_MLINK,
4089336Sdfr	NFSERR_NAMETOL,
4099336Sdfr	NFSERR_NOTEMPTY,
4109336Sdfr	NFSERR_DQUOT,
4119336Sdfr	NFSERR_STALE,
4129336Sdfr	NFSERR_BADHANDLE,
4139336Sdfr	NFSERR_NOTSUPP,
4149336Sdfr	NFSERR_SERVERFAULT,
4159336Sdfr	0,
4169336Sdfr};
4179336Sdfr
4189336Sdfrstatic short nfsv3err_link[] = {
4199336Sdfr	NFSERR_IO,
4209336Sdfr	NFSERR_IO,
4219336Sdfr	NFSERR_ACCES,
4229336Sdfr	NFSERR_EXIST,
4239336Sdfr	NFSERR_XDEV,
4249336Sdfr	NFSERR_NOTDIR,
4259336Sdfr	NFSERR_INVAL,
4269336Sdfr	NFSERR_NOSPC,
4279336Sdfr	NFSERR_ROFS,
4289336Sdfr	NFSERR_MLINK,
4299336Sdfr	NFSERR_NAMETOL,
4309336Sdfr	NFSERR_DQUOT,
4319336Sdfr	NFSERR_STALE,
4329336Sdfr	NFSERR_BADHANDLE,
4339336Sdfr	NFSERR_NOTSUPP,
4349336Sdfr	NFSERR_SERVERFAULT,
4359336Sdfr	0,
4369336Sdfr};
4379336Sdfr
4389336Sdfrstatic short nfsv3err_readdir[] = {
4399336Sdfr	NFSERR_IO,
4409336Sdfr	NFSERR_IO,
4419336Sdfr	NFSERR_ACCES,
4429336Sdfr	NFSERR_NOTDIR,
4439336Sdfr	NFSERR_STALE,
4449336Sdfr	NFSERR_BADHANDLE,
4459336Sdfr	NFSERR_BAD_COOKIE,
4469336Sdfr	NFSERR_TOOSMALL,
4479336Sdfr	NFSERR_SERVERFAULT,
4489336Sdfr	0,
4499336Sdfr};
4509336Sdfr
4519336Sdfrstatic short nfsv3err_readdirplus[] = {
4529336Sdfr	NFSERR_IO,
4539336Sdfr	NFSERR_IO,
4549336Sdfr	NFSERR_ACCES,
4559336Sdfr	NFSERR_NOTDIR,
4569336Sdfr	NFSERR_STALE,
4579336Sdfr	NFSERR_BADHANDLE,
4589336Sdfr	NFSERR_BAD_COOKIE,
4599336Sdfr	NFSERR_NOTSUPP,
4609336Sdfr	NFSERR_TOOSMALL,
4619336Sdfr	NFSERR_SERVERFAULT,
4629336Sdfr	0,
4639336Sdfr};
4649336Sdfr
4659336Sdfrstatic short nfsv3err_fsstat[] = {
4669336Sdfr	NFSERR_IO,
4679336Sdfr	NFSERR_IO,
4689336Sdfr	NFSERR_STALE,
4699336Sdfr	NFSERR_BADHANDLE,
4709336Sdfr	NFSERR_SERVERFAULT,
4719336Sdfr	0,
4729336Sdfr};
4739336Sdfr
4749336Sdfrstatic short nfsv3err_fsinfo[] = {
4759336Sdfr	NFSERR_STALE,
4769336Sdfr	NFSERR_STALE,
4779336Sdfr	NFSERR_BADHANDLE,
4789336Sdfr	NFSERR_SERVERFAULT,
4799336Sdfr	0,
4809336Sdfr};
4819336Sdfr
4829336Sdfrstatic short nfsv3err_pathconf[] = {
4839336Sdfr	NFSERR_STALE,
4849336Sdfr	NFSERR_STALE,
4859336Sdfr	NFSERR_BADHANDLE,
4869336Sdfr	NFSERR_SERVERFAULT,
4879336Sdfr	0,
4889336Sdfr};
4899336Sdfr
4909336Sdfrstatic short nfsv3err_commit[] = {
4919336Sdfr	NFSERR_IO,
4929336Sdfr	NFSERR_IO,
4939336Sdfr	NFSERR_STALE,
4949336Sdfr	NFSERR_BADHANDLE,
4959336Sdfr	NFSERR_SERVERFAULT,
4969336Sdfr	0,
4979336Sdfr};
4989336Sdfr
4999336Sdfrstatic short *nfsrv_v3errmap[] = {
5009336Sdfr	nfsv3err_null,
5019336Sdfr	nfsv3err_getattr,
5029336Sdfr	nfsv3err_setattr,
5039336Sdfr	nfsv3err_lookup,
5049336Sdfr	nfsv3err_access,
5059336Sdfr	nfsv3err_readlink,
5069336Sdfr	nfsv3err_read,
5079336Sdfr	nfsv3err_write,
5089336Sdfr	nfsv3err_create,
5099336Sdfr	nfsv3err_mkdir,
5109336Sdfr	nfsv3err_symlink,
5119336Sdfr	nfsv3err_mknod,
5129336Sdfr	nfsv3err_remove,
5139336Sdfr	nfsv3err_rmdir,
5149336Sdfr	nfsv3err_rename,
5159336Sdfr	nfsv3err_link,
5169336Sdfr	nfsv3err_readdir,
5179336Sdfr	nfsv3err_readdirplus,
5189336Sdfr	nfsv3err_fsstat,
5199336Sdfr	nfsv3err_fsinfo,
5209336Sdfr	nfsv3err_pathconf,
5219336Sdfr	nfsv3err_commit,
5229336Sdfr};
5239336Sdfr
5241541Srgrimes/*
5251541Srgrimes * Called once to initialize data structures...
5261541Srgrimes */
52783651Speterstatic int
52883700Speternfsrv_modevent(module_t mod, int type, void *data)
5291541Srgrimes{
5301541Srgrimes
53183700Speter	switch (type) {
53283700Speter	case MOD_LOAD:
53389094Smsmith		nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
53489094Smsmith		nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
53589094Smsmith		nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
53689094Smsmith		nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
53789094Smsmith		nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
53889094Smsmith		nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
53989094Smsmith		nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR);
54089094Smsmith		nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
54189094Smsmith		nfsrv_nfs_prog = txdr_unsigned(NFS_PROG);
54289094Smsmith		nfsrv_nfs_true = txdr_unsigned(TRUE);
54389094Smsmith		nfsrv_nfs_false = txdr_unsigned(FALSE);
54489094Smsmith		nfsrv_nfs_xdrneg1 = txdr_unsigned(-1);
54589094Smsmith		nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000;
54689094Smsmith		if (nfsrv_ticks < 1)
54789094Smsmith			nfsrv_ticks = 1;
54883651Speter
54983700Speter		nfsrv_init(0);		/* Init server data structures */
55083700Speter		nfsrv_initcache();	/* Init the server request cache */
5511541Srgrimes
55283700Speter		nfsrv_timer(0);
5531541Srgrimes
55483700Speter		nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
55583700Speter		sysent[SYS_nfssvc].sy_narg = 2;
55683700Speter		nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call;
55783700Speter		sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc;
55883700Speter		break;
5592997Swollman
56083700Speter		case MOD_UNLOAD:
56183700Speter
56283700Speter		untimeout(nfsrv_timer, (void *)NULL, nfsrv_timer_handle);
56383700Speter		sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
56483700Speter		sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
56583700Speter		break;
56683700Speter	}
56783700Speter	return 0;
5681541Srgrimes}
56983700Speterstatic moduledata_t nfsserver_mod = {
57083700Speter	"nfsserver",
57183700Speter	nfsrv_modevent,
57283700Speter	NULL,
57383700Speter};
57483700SpeterDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY);
5751541Srgrimes
57683700Speter/* So that loader and kldload(2) can find us, wherever we are.. */
57783700SpeterMODULE_VERSION(nfsserver, 1);
57838894Sbde
5791541Srgrimes/*
58027446Sdfr * Set up nameidata for a lookup() call and do it.
58127446Sdfr *
58227446Sdfr * If pubflag is set, this call is done for a lookup operation on the
58327446Sdfr * public filehandle. In that case we allow crossing mountpoints and
58427446Sdfr * absolute pathnames. However, the caller is expected to check that
58527446Sdfr * the lookup result is within the public fs, and deny access if
58627446Sdfr * it is not.
58748125Sjulian *
58848125Sjulian * nfs_namei() clears out garbage fields that namei() might leave garbage.
58948125Sjulian * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no
59048125Sjulian * error occurs but the parent was not requested.
59148125Sjulian *
59283651Speter * dirp may be set whether an error is returned or not, and must be
59348125Sjulian * released by the caller.
5941541Srgrimes */
5951549Srgrimesint
59683651Speternfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
59783651Speter    struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp,
59883651Speter    caddr_t *dposp, struct vnode **retdirp, struct thread *td, int pubflag)
5991541Srgrimes{
60083651Speter	int i, rem;
60183651Speter	struct mbuf *md;
60283651Speter	char *fromcp, *tocp, *cp;
60327446Sdfr	struct iovec aiov;
60427446Sdfr	struct uio auio;
6051541Srgrimes	struct vnode *dp;
60627446Sdfr	int error, rdonly, linklen;
6071541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
6081541Srgrimes
60999797Sdillon	*retdirp = NULL;
61092783Sjeff	cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
61129653Sdyson
6121541Srgrimes	/*
6131541Srgrimes	 * Copy the name from the mbuf list to ndp->ni_pnbuf
6141541Srgrimes	 * and set the various ndp fields appropriately.
6151541Srgrimes	 */
6161541Srgrimes	fromcp = *dposp;
6171541Srgrimes	tocp = cnp->cn_pnbuf;
6181541Srgrimes	md = *mdp;
6191541Srgrimes	rem = mtod(md, caddr_t) + md->m_len - fromcp;
6201541Srgrimes	for (i = 0; i < len; i++) {
6211541Srgrimes		while (rem == 0) {
6221541Srgrimes			md = md->m_next;
6231541Srgrimes			if (md == NULL) {
6241541Srgrimes				error = EBADRPC;
6251541Srgrimes				goto out;
6261541Srgrimes			}
6271541Srgrimes			fromcp = mtod(md, caddr_t);
6281541Srgrimes			rem = md->m_len;
6291541Srgrimes		}
63027446Sdfr		if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) {
6319336Sdfr			error = EACCES;
6321541Srgrimes			goto out;
6331541Srgrimes		}
6341541Srgrimes		*tocp++ = *fromcp++;
6351541Srgrimes		rem--;
6361541Srgrimes	}
6371541Srgrimes	*tocp = '\0';
6381541Srgrimes	*mdp = md;
6391541Srgrimes	*dposp = fromcp;
6401541Srgrimes	len = nfsm_rndup(len)-len;
6411541Srgrimes	if (len > 0) {
6421541Srgrimes		if (rem >= len)
6431541Srgrimes			*dposp += len;
64427609Sdfr		else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0)
6459336Sdfr			goto out;
6461541Srgrimes	}
64727446Sdfr
6481541Srgrimes	/*
6491541Srgrimes	 * Extract and set starting directory.
6501541Srgrimes	 */
65127446Sdfr	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
65283651Speter	    nam, &rdonly, pubflag);
65327446Sdfr	if (error)
6541541Srgrimes		goto out;
6551541Srgrimes	if (dp->v_type != VDIR) {
65617761Sdyson		vrele(dp);
6571541Srgrimes		error = ENOTDIR;
6581541Srgrimes		goto out;
6591541Srgrimes	}
66027446Sdfr
66127446Sdfr	if (rdonly)
66227446Sdfr		cnp->cn_flags |= RDONLY;
66327446Sdfr
66448125Sjulian	/*
66583651Speter	 * Set return directory.  Reference to dp is implicitly transfered
66648125Sjulian	 * to the returned pointer
66748125Sjulian	 */
66827609Sdfr	*retdirp = dp;
66927609Sdfr
67027446Sdfr	if (pubflag) {
67127446Sdfr		/*
67227446Sdfr		 * Oh joy. For WebNFS, handle those pesky '%' escapes,
67327446Sdfr		 * and the 'native path' indicator.
67427446Sdfr		 */
67592783Sjeff		cp = uma_zalloc(namei_zone, M_WAITOK);
67627446Sdfr		fromcp = cnp->cn_pnbuf;
67727446Sdfr		tocp = cp;
67827446Sdfr		if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) {
67927446Sdfr			switch ((unsigned char)*fromcp) {
68027446Sdfr			case WEBNFS_NATIVE_CHAR:
68127446Sdfr				/*
68227446Sdfr				 * 'Native' path for us is the same
68327446Sdfr				 * as a path according to the NFS spec,
68427446Sdfr				 * just skip the escape char.
68527446Sdfr				 */
68627446Sdfr				fromcp++;
68727446Sdfr				break;
68827446Sdfr			/*
68927446Sdfr			 * More may be added in the future, range 0x80-0xff
69027446Sdfr			 */
69127446Sdfr			default:
69227446Sdfr				error = EIO;
69392783Sjeff				uma_zfree(namei_zone, cp);
69427446Sdfr				goto out;
69527446Sdfr			}
69627446Sdfr		}
69727446Sdfr		/*
69827446Sdfr		 * Translate the '%' escapes, URL-style.
69927446Sdfr		 */
70027446Sdfr		while (*fromcp != '\0') {
70127446Sdfr			if (*fromcp == WEBNFS_ESC_CHAR) {
70227446Sdfr				if (fromcp[1] != '\0' && fromcp[2] != '\0') {
70327446Sdfr					fromcp++;
70427446Sdfr					*tocp++ = HEXSTRTOI(fromcp);
70527446Sdfr					fromcp += 2;
70627446Sdfr					continue;
70727446Sdfr				} else {
70827446Sdfr					error = ENOENT;
70992783Sjeff					uma_zfree(namei_zone, cp);
71027446Sdfr					goto out;
71127446Sdfr				}
71227446Sdfr			} else
71327446Sdfr				*tocp++ = *fromcp++;
71427446Sdfr		}
71527446Sdfr		*tocp = '\0';
71692783Sjeff		uma_zfree(namei_zone, cnp->cn_pnbuf);
71727446Sdfr		cnp->cn_pnbuf = cp;
71827446Sdfr	}
71927446Sdfr
72027446Sdfr	ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1;
72127446Sdfr	ndp->ni_segflg = UIO_SYSSPACE;
72227446Sdfr
72327446Sdfr	if (pubflag) {
72427446Sdfr		ndp->ni_rootdir = rootvnode;
72527446Sdfr		ndp->ni_loopcnt = 0;
72627446Sdfr		if (cnp->cn_pnbuf[0] == '/')
72727446Sdfr			dp = rootvnode;
72827446Sdfr	} else {
72927609Sdfr		cnp->cn_flags |= NOCROSSMOUNT;
73027446Sdfr	}
73127446Sdfr
73248125Sjulian	/*
73348125Sjulian	 * Initialize for scan, set ni_startdir and bump ref on dp again
73448125Sjulian	 * becuase lookup() will dereference ni_startdir.
73548125Sjulian	 */
73648125Sjulian
73783366Sjulian	cnp->cn_thread = td;
7389336Sdfr	VREF(dp);
73948125Sjulian	ndp->ni_startdir = dp;
74027446Sdfr
74148125Sjulian	for (;;) {
74248125Sjulian		cnp->cn_nameptr = cnp->cn_pnbuf;
74348125Sjulian		/*
74448125Sjulian		 * Call lookup() to do the real work.  If an error occurs,
74548125Sjulian		 * ndp->ni_vp and ni_dvp are left uninitialized or NULL and
74648125Sjulian		 * we do not have to dereference anything before returning.
74748125Sjulian		 * In either case ni_startdir will be dereferenced and NULLed
74848125Sjulian		 * out.
74948125Sjulian		 */
75048125Sjulian		error = lookup(ndp);
75148125Sjulian		if (error)
75248125Sjulian			break;
75348125Sjulian
75448125Sjulian		/*
75583651Speter		 * Check for encountering a symbolic link.  Trivial
75648125Sjulian		 * termination occurs if no symlink encountered.
75748125Sjulian		 * Note: zfree is safe because error is 0, so we will
75848125Sjulian		 * not zfree it again when we break.
75948125Sjulian		 */
76048125Sjulian		if ((cnp->cn_flags & ISSYMLINK) == 0) {
76148125Sjulian			nfsrv_object_create(ndp->ni_vp);
76248125Sjulian			if (cnp->cn_flags & (SAVENAME | SAVESTART))
76348125Sjulian				cnp->cn_flags |= HASBUF;
76448125Sjulian			else
76592783Sjeff				uma_zfree(namei_zone, cnp->cn_pnbuf);
76648125Sjulian			break;
76727446Sdfr		}
76848125Sjulian
76948125Sjulian		/*
77048125Sjulian		 * Validate symlink
77148125Sjulian		 */
7721541Srgrimes		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
77383366Sjulian			VOP_UNLOCK(ndp->ni_dvp, 0, td);
77427446Sdfr		if (!pubflag) {
77527446Sdfr			error = EINVAL;
77648125Sjulian			goto badlink2;
77727446Sdfr		}
77827446Sdfr
77927446Sdfr		if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
78027446Sdfr			error = ELOOP;
78148125Sjulian			goto badlink2;
78227446Sdfr		}
78327609Sdfr		if (ndp->ni_pathlen > 1)
78492783Sjeff			cp = uma_zalloc(namei_zone, M_WAITOK);
7851541Srgrimes		else
78627446Sdfr			cp = cnp->cn_pnbuf;
78727446Sdfr		aiov.iov_base = cp;
78827446Sdfr		aiov.iov_len = MAXPATHLEN;
78927446Sdfr		auio.uio_iov = &aiov;
79027446Sdfr		auio.uio_iovcnt = 1;
79127446Sdfr		auio.uio_offset = 0;
79227446Sdfr		auio.uio_rw = UIO_READ;
79327446Sdfr		auio.uio_segflg = UIO_SYSSPACE;
79499797Sdillon		auio.uio_td = NULL;
79527446Sdfr		auio.uio_resid = MAXPATHLEN;
79627446Sdfr		error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred);
79727446Sdfr		if (error) {
79848125Sjulian		badlink1:
79927446Sdfr			if (ndp->ni_pathlen > 1)
80092783Sjeff				uma_zfree(namei_zone, cp);
80148125Sjulian		badlink2:
80248125Sjulian			vrele(ndp->ni_dvp);
80348125Sjulian			vput(ndp->ni_vp);
80427446Sdfr			break;
80527446Sdfr		}
80627446Sdfr		linklen = MAXPATHLEN - auio.uio_resid;
80727446Sdfr		if (linklen == 0) {
80827446Sdfr			error = ENOENT;
80948125Sjulian			goto badlink1;
81027446Sdfr		}
81127446Sdfr		if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
81227446Sdfr			error = ENAMETOOLONG;
81348125Sjulian			goto badlink1;
81427446Sdfr		}
81548125Sjulian
81648125Sjulian		/*
81748125Sjulian		 * Adjust or replace path
81848125Sjulian		 */
81927446Sdfr		if (ndp->ni_pathlen > 1) {
82027446Sdfr			bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
82192783Sjeff			uma_zfree(namei_zone, cnp->cn_pnbuf);
82227446Sdfr			cnp->cn_pnbuf = cp;
82327446Sdfr		} else
82427446Sdfr			cnp->cn_pnbuf[linklen] = '\0';
82527446Sdfr		ndp->ni_pathlen += linklen;
82648125Sjulian
82727446Sdfr		/*
82883651Speter		 * Cleanup refs for next loop and check if root directory
82983651Speter		 * should replace current directory.  Normally ni_dvp
83048125Sjulian		 * becomes the new base directory and is cleaned up when
83148125Sjulian		 * we loop.  Explicitly null pointers after invalidation
83248125Sjulian		 * to clarify operation.
83327446Sdfr		 */
83448125Sjulian		vput(ndp->ni_vp);
83548125Sjulian		ndp->ni_vp = NULL;
83648125Sjulian
83727446Sdfr		if (cnp->cn_pnbuf[0] == '/') {
83848125Sjulian			vrele(ndp->ni_dvp);
83948125Sjulian			ndp->ni_dvp = ndp->ni_rootdir;
84048125Sjulian			VREF(ndp->ni_dvp);
84127446Sdfr		}
84248125Sjulian		ndp->ni_startdir = ndp->ni_dvp;
84348125Sjulian		ndp->ni_dvp = NULL;
8441541Srgrimes	}
84548125Sjulian
84648125Sjulian	/*
84748125Sjulian	 * nfs_namei() guarentees that fields will not contain garbage
84848125Sjulian	 * whether an error occurs or not.  This allows the caller to track
84948125Sjulian	 * cleanup state trivially.
85048125Sjulian	 */
8511541Srgrimesout:
85248125Sjulian	if (error) {
85392783Sjeff		uma_zfree(namei_zone, cnp->cn_pnbuf);
85448125Sjulian		ndp->ni_vp = NULL;
85548125Sjulian		ndp->ni_dvp = NULL;
85648125Sjulian		ndp->ni_startdir = NULL;
85748125Sjulian		cnp->cn_flags &= ~HASBUF;
85848125Sjulian	} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
85948125Sjulian		ndp->ni_dvp = NULL;
86048125Sjulian	}
8611541Srgrimes	return (error);
8621541Srgrimes}
8631541Srgrimes
8641541Srgrimes/*
8651541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long
8661541Srgrimes * boundary and only trims off the back end
8671541Srgrimes */
8681541Srgrimesvoid
86983651Speternfsm_adj(struct mbuf *mp, int len, int nul)
8701541Srgrimes{
87183651Speter	struct mbuf *m;
87283651Speter	int count, i;
87383651Speter	char *cp;
8741541Srgrimes
8751541Srgrimes	/*
8761541Srgrimes	 * Trim from tail.  Scan the mbuf chain,
8771541Srgrimes	 * calculating its length and finding the last mbuf.
8781541Srgrimes	 * If the adjustment only affects this mbuf, then just
8791541Srgrimes	 * adjust and return.  Otherwise, rescan and truncate
8801541Srgrimes	 * after the remaining size.
8811541Srgrimes	 */
8821541Srgrimes	count = 0;
8831541Srgrimes	m = mp;
8841541Srgrimes	for (;;) {
8851541Srgrimes		count += m->m_len;
88699797Sdillon		if (m->m_next == NULL)
8871541Srgrimes			break;
8881541Srgrimes		m = m->m_next;
8891541Srgrimes	}
8901541Srgrimes	if (m->m_len > len) {
8911541Srgrimes		m->m_len -= len;
8921541Srgrimes		if (nul > 0) {
8931541Srgrimes			cp = mtod(m, caddr_t)+m->m_len-nul;
8941541Srgrimes			for (i = 0; i < nul; i++)
8951541Srgrimes				*cp++ = '\0';
8961541Srgrimes		}
8971541Srgrimes		return;
8981541Srgrimes	}
8991541Srgrimes	count -= len;
9001541Srgrimes	if (count < 0)
9011541Srgrimes		count = 0;
9021541Srgrimes	/*
9031541Srgrimes	 * Correct length for chain is "count".
9041541Srgrimes	 * Find the mbuf with last data, adjust its length,
9051541Srgrimes	 * and toss data from remaining mbufs on chain.
9061541Srgrimes	 */
9071541Srgrimes	for (m = mp; m; m = m->m_next) {
9081541Srgrimes		if (m->m_len >= count) {
9091541Srgrimes			m->m_len = count;
9101541Srgrimes			if (nul > 0) {
9111541Srgrimes				cp = mtod(m, caddr_t)+m->m_len-nul;
9121541Srgrimes				for (i = 0; i < nul; i++)
9131541Srgrimes					*cp++ = '\0';
9141541Srgrimes			}
9151541Srgrimes			break;
9161541Srgrimes		}
9171541Srgrimes		count -= m->m_len;
9181541Srgrimes	}
9193305Sphk	for (m = m->m_next;m;m = m->m_next)
9201541Srgrimes		m->m_len = 0;
9211541Srgrimes}
9221541Srgrimes
9231541Srgrimes/*
9249336Sdfr * Make these functions instead of macros, so that the kernel text size
9259336Sdfr * doesn't get too big...
9269336Sdfr */
9279336Sdfrvoid
92883651Speternfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret,
92983651Speter    struct vattr *before_vap, int after_ret, struct vattr *after_vap,
93083651Speter    struct mbuf **mbp, char **bposp)
9319336Sdfr{
93283651Speter	struct mbuf *mb = *mbp;
93383651Speter	char *bpos = *bposp;
93483651Speter	u_int32_t *tl;
9359336Sdfr
9369336Sdfr	if (before_ret) {
93784002Speter		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
93889094Smsmith		*tl = nfsrv_nfs_false;
9399336Sdfr	} else {
94084002Speter		tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED);
94189094Smsmith		*tl++ = nfsrv_nfs_true;
94247751Speter		txdr_hyper(before_vap->va_size, tl);
9439336Sdfr		tl += 2;
9449336Sdfr		txdr_nfsv3time(&(before_vap->va_mtime), tl);
9459336Sdfr		tl += 2;
9469336Sdfr		txdr_nfsv3time(&(before_vap->va_ctime), tl);
9479336Sdfr	}
9489336Sdfr	*bposp = bpos;
9499336Sdfr	*mbp = mb;
9509336Sdfr	nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp);
9519336Sdfr}
9529336Sdfr
9539336Sdfrvoid
95483651Speternfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret,
95583651Speter    struct vattr *after_vap, struct mbuf **mbp, char **bposp)
9569336Sdfr{
95783651Speter	struct mbuf *mb = *mbp;
95883651Speter	char *bpos = *bposp;
95983651Speter	u_int32_t *tl;
96083651Speter	struct nfs_fattr *fp;
9619336Sdfr
9629336Sdfr	if (after_ret) {
96384002Speter		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
96489094Smsmith		*tl = nfsrv_nfs_false;
9659336Sdfr	} else {
96684002Speter		tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR);
96789094Smsmith		*tl++ = nfsrv_nfs_true;
9689336Sdfr		fp = (struct nfs_fattr *)tl;
9699336Sdfr		nfsm_srvfattr(nfsd, after_vap, fp);
9709336Sdfr	}
9719336Sdfr	*mbp = mb;
9729336Sdfr	*bposp = bpos;
9739336Sdfr}
9749336Sdfr
9759336Sdfrvoid
97683651Speternfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap,
97783651Speter    struct nfs_fattr *fp)
9789336Sdfr{
9799336Sdfr
9809336Sdfr	fp->fa_nlink = txdr_unsigned(vap->va_nlink);
9819336Sdfr	fp->fa_uid = txdr_unsigned(vap->va_uid);
9829336Sdfr	fp->fa_gid = txdr_unsigned(vap->va_gid);
9839336Sdfr	if (nfsd->nd_flag & ND_NFSV3) {
9849336Sdfr		fp->fa_type = vtonfsv3_type(vap->va_type);
9859336Sdfr		fp->fa_mode = vtonfsv3_mode(vap->va_mode);
98647751Speter		txdr_hyper(vap->va_size, &fp->fa3_size);
98747751Speter		txdr_hyper(vap->va_bytes, &fp->fa3_used);
98847028Sphk		fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev));
98947028Sphk		fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev));
9909336Sdfr		fp->fa3_fsid.nfsuquad[0] = 0;
9919336Sdfr		fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid);
9929336Sdfr		fp->fa3_fileid.nfsuquad[0] = 0;
9939336Sdfr		fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid);
9949336Sdfr		txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime);
9959336Sdfr		txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime);
9969336Sdfr		txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime);
9979336Sdfr	} else {
9989336Sdfr		fp->fa_type = vtonfsv2_type(vap->va_type);
9999336Sdfr		fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode);
10009336Sdfr		fp->fa2_size = txdr_unsigned(vap->va_size);
10019336Sdfr		fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize);
10029336Sdfr		if (vap->va_type == VFIFO)
10039336Sdfr			fp->fa2_rdev = 0xffffffff;
10049336Sdfr		else
10059336Sdfr			fp->fa2_rdev = txdr_unsigned(vap->va_rdev);
10069336Sdfr		fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE);
10079336Sdfr		fp->fa2_fsid = txdr_unsigned(vap->va_fsid);
10089336Sdfr		fp->fa2_fileid = txdr_unsigned(vap->va_fileid);
10099336Sdfr		txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime);
10109336Sdfr		txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime);
10119336Sdfr		txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime);
10129336Sdfr	}
10139336Sdfr}
10149336Sdfr
10159336Sdfr/*
10161541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
10171541Srgrimes * 	- look up fsid in mount list (if not found ret error)
10181541Srgrimes *	- get vp and export rights by calling VFS_FHTOVP()
10191541Srgrimes *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
10201541Srgrimes *	- if not lockflag unlock it with VOP_UNLOCK()
10211541Srgrimes */
10221549Srgrimesint
102383651Speternfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
102483651Speter    struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam,
102583651Speter    int *rdonlyp, int pubflag)
10261541Srgrimes{
102783366Sjulian	struct thread *td = curthread; /* XXX */
102883651Speter	struct mount *mp;
102983651Speter	int i;
10301541Srgrimes	struct ucred *credanon;
10311541Srgrimes	int error, exflags;
103236534Speter#ifdef MNT_EXNORESPORT		/* XXX needs mountd and /etc/exports help yet */
103336534Speter	struct sockaddr_int *saddr;
103436534Speter#endif
10351541Srgrimes
103699797Sdillon	*vpp = NULL;
103727446Sdfr
103827446Sdfr	if (nfs_ispublicfh(fhp)) {
103927446Sdfr		if (!pubflag || !nfs_pub.np_valid)
104027446Sdfr			return (ESTALE);
104127446Sdfr		fhp = &nfs_pub.np_handle;
104227446Sdfr	}
104327446Sdfr
104422521Sdyson	mp = vfs_getvfs(&fhp->fh_fsid);
10453305Sphk	if (!mp)
10461541Srgrimes		return (ESTALE);
104751138Salfred	error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
10483305Sphk	if (error)
104983651Speter		return (error);
105051138Salfred	error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
105151138Salfred	if (error)
10521541Srgrimes		return (error);
105336534Speter#ifdef MNT_EXNORESPORT
105436534Speter	if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
105536534Speter		saddr = (struct sockaddr_in *)nam;
1056100134Salfred		if ((saddr->sin_family == AF_INET ||
1057100134Salfred		     saddr->sin_family == AF_INET6) &&
1058100134Salfred	/* same code for INET and INET6: sin*_port at same offet */
105936534Speter		    ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
106036534Speter			vput(*vpp);
106154485Sdillon			*vpp = NULL;
106236534Speter			return (NFSERR_AUTHERR | AUTH_TOOWEAK);
106336534Speter		}
106436534Speter	}
106536534Speter#endif
10661541Srgrimes	/*
10671541Srgrimes	 * Check/setup credentials.
10681541Srgrimes	 */
106983651Speter	if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
10701541Srgrimes		cred->cr_uid = credanon->cr_uid;
10711541Srgrimes		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
10721541Srgrimes			cred->cr_groups[i] = credanon->cr_groups[i];
10733664Sphk		cred->cr_ngroups = i;
10741541Srgrimes	}
10751541Srgrimes	if (exflags & MNT_EXRDONLY)
10761541Srgrimes		*rdonlyp = 1;
10771541Srgrimes	else
10781541Srgrimes		*rdonlyp = 0;
10797969Sdyson
108017761Sdyson	nfsrv_object_create(*vpp);
10817969Sdyson
10821541Srgrimes	if (!lockflag)
108383366Sjulian		VOP_UNLOCK(*vpp, 0, td);
10841541Srgrimes	return (0);
10851541Srgrimes}
10861541Srgrimes
108727446Sdfr
108827446Sdfr/*
108927446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this
109027446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has
109127446Sdfr * transformed this to all zeroes in both cases, so check for it.
109227446Sdfr */
109327446Sdfrint
109483651Speternfs_ispublicfh(fhandle_t *fhp)
109527446Sdfr{
109627446Sdfr	char *cp = (char *)fhp;
109727446Sdfr	int i;
109827446Sdfr
109927446Sdfr	for (i = 0; i < NFSX_V3FH; i++)
110027446Sdfr		if (*cp++ != 0)
110127446Sdfr			return (FALSE);
110227446Sdfr	return (TRUE);
110327446Sdfr}
110483651Speter
11051541Srgrimes/*
11061541Srgrimes * This function compares two net addresses by family and returns TRUE
11071541Srgrimes * if they are the same host.
11081541Srgrimes * If there is any doubt, return FALSE.
11091541Srgrimes * The AF_INET family is handled as a special case so that address mbufs
11101541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes.
11111541Srgrimes */
11121549Srgrimesint
111383651Speternetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
11141541Srgrimes{
111583651Speter	struct sockaddr_in *inetaddr;
11161541Srgrimes
11171541Srgrimes	switch (family) {
11181541Srgrimes	case AF_INET:
111928270Swollman		inetaddr = (struct sockaddr_in *)nam;
11201541Srgrimes		if (inetaddr->sin_family == AF_INET &&
11211541Srgrimes		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
11221541Srgrimes			return (1);
11231541Srgrimes		break;
1124100134Salfred#ifdef INET6
1125100134Salfred	case AF_INET6:
1126100134Salfred	{
1127100134Salfred		register struct sockaddr_in6 *inet6addr1, *inet6addr2;
1128100134Salfred
1129100134Salfred		inet6addr1 = (struct sockaddr_in6 *)nam;
1130100134Salfred		inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam;
1131100134Salfred	/* XXX - should test sin6_scope_id ? */
1132100134Salfred		if (inet6addr1->sin6_family == AF_INET6 &&
1133100134Salfred		    IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr,
1134100134Salfred				       &inet6addr2->sin6_addr))
1135100134Salfred			return (1);
1136100134Salfred		break;
1137100134Salfred	}
1138100134Salfred#endif
11391541Srgrimes	default:
11401541Srgrimes		break;
11411541Srgrimes	};
11421541Srgrimes	return (0);
11431541Srgrimes}
11445455Sdg
11459336Sdfr/*
11469336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error
11479336Sdfr * numbers not specified for the associated procedure.
11489336Sdfr */
11495455Sdgint
115083651Speternfsrv_errmap(struct nfsrv_descript *nd, int err)
11519336Sdfr{
115283651Speter	short *defaulterrp, *errp;
11539336Sdfr
11549336Sdfr	if (nd->nd_flag & ND_NFSV3) {
11559336Sdfr	    if (nd->nd_procnum <= NFSPROC_COMMIT) {
11569336Sdfr		errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
11579336Sdfr		while (*++errp) {
11589336Sdfr			if (*errp == err)
11599336Sdfr				return (err);
11609336Sdfr			else if (*errp > err)
11619336Sdfr				break;
11629336Sdfr		}
11639336Sdfr		return ((int)*defaulterrp);
11649336Sdfr	    } else
11659336Sdfr		return (err & 0xffff);
11669336Sdfr	}
11679336Sdfr	if (err <= ELAST)
11689336Sdfr		return ((int)nfsrv_v2errmap[err - 1]);
11699336Sdfr	return (NFSERR_IO);
11709336Sdfr}
11719336Sdfr
11729336Sdfrint
117383651Speternfsrv_object_create(struct vnode *vp)
117431886Sbde{
11755455Sdg
117631886Sbde	if (vp == NULL || vp->v_type != VREG)
117731886Sbde		return (1);
117891406Sjhb	return (vfs_object_create(vp, curthread, curthread->td_ucred));
11795455Sdg}
118036503Speter
118136503Speter/*
118236503Speter * Sort the group list in increasing numerical order.
118336503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
118436503Speter *  that used to be here.)
118536503Speter */
118636503Spetervoid
118783651Speternfsrvw_sort(gid_t *list, int num)
118836503Speter{
118983651Speter	int i, j;
119036503Speter	gid_t v;
119136503Speter
119236503Speter	/* Insertion sort. */
119336503Speter	for (i = 1; i < num; i++) {
119436503Speter		v = list[i];
119536503Speter		/* find correct slot for value v, moving others up */
119636503Speter		for (j = i; --j >= 0 && v < list[j];)
119736503Speter			list[j + 1] = list[j];
119836503Speter		list[j + 1] = v;
119936503Speter	}
120036503Speter}
120136503Speter
120236503Speter/*
120336503Speter * copy credentials making sure that the result can be compared with bcmp().
120436503Speter */
120536503Spetervoid
120683651Speternfsrv_setcred(struct ucred *incred, struct ucred *outcred)
120736503Speter{
120883651Speter	int i;
120936503Speter
121036503Speter	bzero((caddr_t)outcred, sizeof (struct ucred));
121136503Speter	outcred->cr_ref = 1;
121236503Speter	outcred->cr_uid = incred->cr_uid;
121336503Speter	outcred->cr_ngroups = incred->cr_ngroups;
121436503Speter	for (i = 0; i < incred->cr_ngroups; i++)
121536503Speter		outcred->cr_groups[i] = incred->cr_groups[i];
121636503Speter	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
121736503Speter}
121883651Speter
121983651Speter/*
122083651Speter * Helper functions for macros.
122183651Speter */
122283651Speter
122383651Spetervoid
122488091Siedowsenfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
122583651Speter{
122688091Siedowse	u_int32_t *tl;
122783651Speter
122883651Speter	if (v3) {
122988091Siedowse		tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
123088091Siedowse		*tl++ = txdr_unsigned(NFSX_V3FH);
123188091Siedowse		bcopy(f, tl, NFSX_V3FH);
123283651Speter	} else {
123388091Siedowse		tl = nfsm_build_xx(NFSX_V2FH, mb, bpos);
123488091Siedowse		bcopy(f, tl, NFSX_V2FH);
123583651Speter	}
123683651Speter}
123783651Speter
123883651Spetervoid
123988091Siedowsenfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos)
124083651Speter{
124188091Siedowse	u_int32_t *tl;
124284002Speter
124388091Siedowse	tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
124489094Smsmith	*tl++ = nfsrv_nfs_true;
124588091Siedowse	*tl++ = txdr_unsigned(NFSX_V3FH);
124688091Siedowse	bcopy(f, tl, NFSX_V3FH);
124783651Speter}
124883651Speter
124983651Speterint
125088091Siedowsenfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
125183651Speter{
125288091Siedowse	u_int32_t *tl;
125383651Speter
125488091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
125588091Siedowse	if (tl == NULL)
125684057Speter		return EBADRPC;
125788091Siedowse	*s = fxdr_unsigned(int32_t, *tl);
125883651Speter	if (*s > m || *s <= 0)
125983651Speter		return EBADRPC;
126083651Speter	return 0;
126183651Speter}
126283651Speter
126383651Speterint
126488091Siedowsenfsm_srvnamesiz_xx(int *s, struct mbuf **md, caddr_t *dpos)
126583651Speter{
126688091Siedowse	u_int32_t *tl;
126783651Speter
126888091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
126988091Siedowse	if (tl == NULL)
127084057Speter		return EBADRPC;
127188091Siedowse	*s = fxdr_unsigned(int32_t, *tl);
127283651Speter	if (*s > NFS_MAXNAMLEN)
127383651Speter		return NFSERR_NAMETOL;
127483651Speter	if (*s <= 0)
127583651Speter		return EBADRPC;
127683651Speter	return 0;
127783651Speter}
127883651Speter
127983651Spetervoid
128083651Speternfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
128183651Speter    char **bp, char **be, caddr_t bpos)
128283651Speter{
128383651Speter	struct mbuf *nmp;
128483651Speter
128583651Speter	if (*bp >= *be) {
128683651Speter		if (*mp == mb)
128783651Speter			(*mp)->m_len += *bp - bpos;
128883651Speter		MGET(nmp, M_TRYWAIT, MT_DATA);
128983651Speter		MCLGET(nmp, M_TRYWAIT);
129083651Speter		nmp->m_len = NFSMSIZ(nmp);
129183651Speter		(*mp)->m_next = nmp;
129283651Speter		*mp = nmp;
129383651Speter		*bp = mtod(*mp, caddr_t);
129483651Speter		*be = *bp + (*mp)->m_len;
129583651Speter	}
129683651Speter	*tl = (u_int32_t *)*bp;
129783651Speter}
129883651Speter
129983651Speterint
130088091Siedowsenfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
130188091Siedowse    caddr_t *dpos)
130283651Speter{
130388091Siedowse	u_int32_t *tl;
130483651Speter	int fhlen;
130583651Speter
130683651Speter	if (nfsd->nd_flag & ND_NFSV3) {
130788091Siedowse		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
130888091Siedowse		if (tl == NULL)
130984057Speter			return EBADRPC;
131088091Siedowse		fhlen = fxdr_unsigned(int, *tl);
131183651Speter		if (fhlen != 0 && fhlen != NFSX_V3FH)
131283651Speter			return EBADRPC;
131383651Speter	} else {
131483651Speter		fhlen = NFSX_V2FH;
131583651Speter	}
131683651Speter	if (fhlen != 0) {
131788091Siedowse		tl = nfsm_dissect_xx(fhlen, md, dpos);
131888091Siedowse		if (tl == NULL)
131984057Speter			return EBADRPC;
132088091Siedowse		bcopy((caddr_t)tl, (caddr_t)(f), fhlen);
132183651Speter	} else {
132283651Speter		bzero((caddr_t)(f), NFSX_V3FH);
132383651Speter	}
132483651Speter	return 0;
132583651Speter}
132683651Speter
132783651Speterint
132888091Siedowsenfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
132983651Speter{
133088091Siedowse	u_int32_t *tl;
133183651Speter
133288091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
133388091Siedowse	if (tl == NULL)
133484057Speter		return EBADRPC;
133589094Smsmith	if (*tl == nfsrv_nfs_true) {
133688091Siedowse		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
133788091Siedowse		if (tl == NULL)
133884057Speter			return EBADRPC;
133988091Siedowse		(a)->va_mode = nfstov_mode(*tl);
134083651Speter	}
134188091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
134288091Siedowse	if (tl == NULL)
134384057Speter		return EBADRPC;
134489094Smsmith	if (*tl == nfsrv_nfs_true) {
134588091Siedowse		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
134688091Siedowse		if (tl == NULL)
134784057Speter			return EBADRPC;
134888091Siedowse		(a)->va_uid = fxdr_unsigned(uid_t, *tl);
134983651Speter	}
135088091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
135188091Siedowse	if (tl == NULL)
135284057Speter		return EBADRPC;
135389094Smsmith	if (*tl == nfsrv_nfs_true) {
135488091Siedowse		tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
135588091Siedowse		if (tl == NULL)
135684057Speter			return EBADRPC;
135788091Siedowse		(a)->va_gid = fxdr_unsigned(gid_t, *tl);
135883651Speter	}
135988091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
136088091Siedowse	if (tl == NULL)
136184057Speter		return EBADRPC;
136289094Smsmith	if (*tl == nfsrv_nfs_true) {
136388091Siedowse		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
136488091Siedowse		if (tl == NULL)
136584057Speter			return EBADRPC;
136688091Siedowse		(a)->va_size = fxdr_hyper(tl);
136783651Speter	}
136888091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
136988091Siedowse	if (tl == NULL)
137084057Speter		return EBADRPC;
137188091Siedowse	switch (fxdr_unsigned(int, *tl)) {
137283651Speter	case NFSV3SATTRTIME_TOCLIENT:
137388091Siedowse		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
137488091Siedowse		if (tl == NULL)
137584057Speter			return EBADRPC;
137688091Siedowse		fxdr_nfsv3time(tl, &(a)->va_atime);
137783651Speter		break;
137883651Speter	case NFSV3SATTRTIME_TOSERVER:
137983651Speter		getnanotime(&(a)->va_atime);
138083651Speter		break;
138183651Speter	}
138288091Siedowse	tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
138388091Siedowse	if (tl == NULL)
138484057Speter		return EBADRPC;
138588091Siedowse	switch (fxdr_unsigned(int, *tl)) {
138683651Speter	case NFSV3SATTRTIME_TOCLIENT:
138788091Siedowse		tl = nfsm_dissect_xx(2 * NFSX_UNSIGNED, md, dpos);
138888091Siedowse		if (tl == NULL)
138984057Speter			return EBADRPC;
139088091Siedowse		fxdr_nfsv3time(tl, &(a)->va_mtime);
139183651Speter		break;
139283651Speter	case NFSV3SATTRTIME_TOSERVER:
139383651Speter		getnanotime(&(a)->va_mtime);
139483651Speter		break;
139583651Speter	}
139683651Speter	return 0;
139783651Speter}
1398