nfs_srvsubs.c revision 182371
1139823Simp/*- 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 * 4. Neither the name of the University nor the names of its contributors 171541Srgrimes * may be used to endorse or promote products derived from this software 181541Srgrimes * without specific prior written permission. 191541Srgrimes * 201541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301541Srgrimes * SUCH DAMAGE. 311541Srgrimes * 3236503Speter * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 331541Srgrimes */ 341541Srgrimes 3583651Speter#include <sys/cdefs.h> 3683651Speter__FBSDID("$FreeBSD: head/sys/nfsserver/nfs_srvsubs.c 182371 2008-08-28 15:23:18Z attilio $"); 3783651Speter 381541Srgrimes/* 391541Srgrimes * These functions support the macros and help fiddle mbuf chains for 401541Srgrimes * the nfs op functions. They do things like create the rpc header and 411541Srgrimes * copy data between mbuf chains and uio lists. 421541Srgrimes */ 4383651Speter 44100134Salfred#include "opt_inet6.h" 45100134Salfred 461541Srgrimes#include <sys/param.h> 4748274Speter#include <sys/systm.h> 4848274Speter#include <sys/kernel.h> 4960041Sphk#include <sys/bio.h> 5031886Sbde#include <sys/buf.h> 511541Srgrimes#include <sys/proc.h> 521541Srgrimes#include <sys/mount.h> 531541Srgrimes#include <sys/vnode.h> 541541Srgrimes#include <sys/namei.h> 551541Srgrimes#include <sys/mbuf.h> 56150634Sjhb#include <sys/refcount.h> 571541Srgrimes#include <sys/socket.h> 581541Srgrimes#include <sys/stat.h> 599336Sdfr#include <sys/malloc.h> 6083700Speter#include <sys/module.h> 612997Swollman#include <sys/sysent.h> 622997Swollman#include <sys/syscall.h> 6383651Speter#include <sys/sysproto.h> 641541Srgrimes 653305Sphk#include <vm/vm.h> 6612662Sdg#include <vm/vm_object.h> 6712662Sdg#include <vm/vm_extern.h> 6892783Sjeff#include <vm/uma.h> 693305Sphk 701541Srgrimes#include <nfs/rpcv2.h> 719336Sdfr#include <nfs/nfsproto.h> 7283651Speter#include <nfsserver/nfs.h> 731541Srgrimes#include <nfs/xdr_subs.h> 7483651Speter#include <nfsserver/nfsm_subs.h> 751541Srgrimes 761541Srgrimes#include <netinet/in.h> 771541Srgrimes 781541Srgrimes/* 791541Srgrimes * Data items converted to xdr at startup, since they are constant 801541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 811541Srgrimes */ 8289094Smsmithu_int32_t nfsrv_nfs_xdrneg1; 8389094Smsmithu_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply, 8489094Smsmith nfsrv_rpc_msgdenied, nfsrv_rpc_autherr, 8589094Smsmith nfsrv_rpc_mismatch, nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted; 8689094Smsmithu_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false; 871541Srgrimes 881541Srgrimes/* And other global data */ 89129639Srwatsonstatic const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, 90129639Srwatson NFLNK, NFNON, NFCHR, NFNON }; 9183651Speter#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))]) 9283651Speter#define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS) 9312911Sphk 9489094Smsmithint nfsrv_ticks; 959336Sdfr 969759Sbdestruct nfssvc_sockhead nfssvc_sockhead; 979759Sbdeint nfssvc_sockhead_flag; 989759Sbdestruct nfsd_head nfsd_head; 999759Sbdeint nfsd_head_flag; 1009759Sbde 101168268Sjhbstatic int nfssvc_offset = SYS_nfssvc; 102168268Sjhbstatic struct sysent nfssvc_prev_sysent; 103168268SjhbMAKE_SYSENT(nfssvc); 10438894Sbde 105129639Srwatsonstruct mtx nfsd_mtx; 106129639Srwatson 1079336Sdfr/* 1089336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 1099336Sdfr */ 110129639Srwatsonconst int nfsrv_nfsv3_procid[NFS_NPROCS] = { 1119336Sdfr NFSPROC_NULL, 1129336Sdfr NFSPROC_GETATTR, 1139336Sdfr NFSPROC_SETATTR, 1149336Sdfr NFSPROC_NOOP, 1159336Sdfr NFSPROC_LOOKUP, 1169336Sdfr NFSPROC_READLINK, 1179336Sdfr NFSPROC_READ, 1189336Sdfr NFSPROC_NOOP, 1199336Sdfr NFSPROC_WRITE, 1209336Sdfr NFSPROC_CREATE, 1219336Sdfr NFSPROC_REMOVE, 1229336Sdfr NFSPROC_RENAME, 1239336Sdfr NFSPROC_LINK, 1249336Sdfr NFSPROC_SYMLINK, 1259336Sdfr NFSPROC_MKDIR, 1269336Sdfr NFSPROC_RMDIR, 1279336Sdfr NFSPROC_READDIR, 1289336Sdfr NFSPROC_FSSTAT, 1299336Sdfr NFSPROC_NOOP, 1309336Sdfr NFSPROC_NOOP, 1319336Sdfr NFSPROC_NOOP, 1329336Sdfr NFSPROC_NOOP, 1339336Sdfr NFSPROC_NOOP, 1349336Sdfr}; 1359336Sdfr 1369336Sdfr/* 1379336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1389336Sdfr */ 139129639Srwatsonconst int nfsrvv2_procid[NFS_NPROCS] = { 1409336Sdfr NFSV2PROC_NULL, 1419336Sdfr NFSV2PROC_GETATTR, 1429336Sdfr NFSV2PROC_SETATTR, 1439336Sdfr NFSV2PROC_LOOKUP, 1449336Sdfr NFSV2PROC_NOOP, 1459336Sdfr NFSV2PROC_READLINK, 1469336Sdfr NFSV2PROC_READ, 1479336Sdfr NFSV2PROC_WRITE, 1489336Sdfr NFSV2PROC_CREATE, 1499336Sdfr NFSV2PROC_MKDIR, 1509336Sdfr NFSV2PROC_SYMLINK, 1519336Sdfr NFSV2PROC_CREATE, 1529336Sdfr NFSV2PROC_REMOVE, 1539336Sdfr NFSV2PROC_RMDIR, 1549336Sdfr NFSV2PROC_RENAME, 1559336Sdfr NFSV2PROC_LINK, 1569336Sdfr NFSV2PROC_READDIR, 1579336Sdfr NFSV2PROC_NOOP, 1589336Sdfr NFSV2PROC_STATFS, 1599336Sdfr NFSV2PROC_NOOP, 1609336Sdfr NFSV2PROC_NOOP, 1619336Sdfr NFSV2PROC_NOOP, 1629336Sdfr NFSV2PROC_NOOP, 1639336Sdfr}; 1649336Sdfr 1659336Sdfr/* 1669336Sdfr * Maps errno values to nfs error numbers. 167102236Sphk * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not 168102236Sphk * specifically defined in RFC 1094. 1699336Sdfr */ 170129639Srwatsonstatic const u_char nfsrv_v2errmap[ELAST] = { 171102236Sphk NFSERR_PERM, NFSERR_NOENT, 0, 0, 0, 172102236Sphk NFSERR_NXIO, 0, 0, 0, 0, 173102236Sphk 0, 0, NFSERR_ACCES, 0, 0, 174102236Sphk 0, NFSERR_EXIST, 0, NFSERR_NODEV, NFSERR_NOTDIR, 175102236Sphk NFSERR_ISDIR, 0, 0, 0, 0, 176102236Sphk 0, NFSERR_FBIG, NFSERR_NOSPC, 0, NFSERR_ROFS, 177102236Sphk 0, 0, 0, 0, 0, 178102236Sphk 0, 0, 0, 0, 0, 179102236Sphk 0, 0, 0, 0, 0, 180102236Sphk 0, 0, 0, 0, 0, 181102236Sphk 0, 0, 0, 0, 0, 182102236Sphk 0, 0, 0, 0, 0, 183102236Sphk 0, 0, NFSERR_NAMETOL, 0, 0, 184102236Sphk NFSERR_NOTEMPTY, 0, 0, NFSERR_DQUOT, NFSERR_STALE, 185102236Sphk 0 1869336Sdfr}; 1879336Sdfr 1889336Sdfr/* 1899336Sdfr * Maps errno values to nfs error numbers. 1909336Sdfr * Although it is not obvious whether or not NFS clients really care if 1919336Sdfr * a returned error value is in the specified list for the procedure, the 1929336Sdfr * safest thing to do is filter them appropriately. For Version 2, the 1939336Sdfr * X/Open XNFS document is the only specification that defines error values 1949336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs), 1959336Sdfr * so I have decided to not do this for Version 2. 1969336Sdfr * The first entry is the default error return and the rest are the valid 1979336Sdfr * errors for that RPC in increasing numeric order. 1989336Sdfr */ 199129639Srwatsonstatic const short nfsv3err_null[] = { 2009336Sdfr 0, 2019336Sdfr 0, 2029336Sdfr}; 2039336Sdfr 204129639Srwatsonstatic const short nfsv3err_getattr[] = { 2059336Sdfr NFSERR_IO, 2069336Sdfr NFSERR_IO, 2079336Sdfr NFSERR_STALE, 2089336Sdfr NFSERR_BADHANDLE, 2099336Sdfr NFSERR_SERVERFAULT, 2109336Sdfr 0, 2119336Sdfr}; 2129336Sdfr 213129639Srwatsonstatic const short nfsv3err_setattr[] = { 2149336Sdfr NFSERR_IO, 2159336Sdfr NFSERR_PERM, 2169336Sdfr NFSERR_IO, 2179336Sdfr NFSERR_ACCES, 2189336Sdfr NFSERR_INVAL, 2199336Sdfr NFSERR_NOSPC, 2209336Sdfr NFSERR_ROFS, 2219336Sdfr NFSERR_DQUOT, 2229336Sdfr NFSERR_STALE, 2239336Sdfr NFSERR_BADHANDLE, 2249336Sdfr NFSERR_NOT_SYNC, 2259336Sdfr NFSERR_SERVERFAULT, 2269336Sdfr 0, 2279336Sdfr}; 2289336Sdfr 229129639Srwatsonstatic const short nfsv3err_lookup[] = { 2309336Sdfr NFSERR_IO, 2319336Sdfr NFSERR_NOENT, 2329336Sdfr NFSERR_IO, 2339336Sdfr NFSERR_ACCES, 2349336Sdfr NFSERR_NOTDIR, 2359336Sdfr NFSERR_NAMETOL, 2369336Sdfr NFSERR_STALE, 2379336Sdfr NFSERR_BADHANDLE, 2389336Sdfr NFSERR_SERVERFAULT, 2399336Sdfr 0, 2409336Sdfr}; 2419336Sdfr 242129639Srwatsonstatic const short nfsv3err_access[] = { 2439336Sdfr NFSERR_IO, 2449336Sdfr NFSERR_IO, 2459336Sdfr NFSERR_STALE, 2469336Sdfr NFSERR_BADHANDLE, 2479336Sdfr NFSERR_SERVERFAULT, 2489336Sdfr 0, 2499336Sdfr}; 2509336Sdfr 251129639Srwatsonstatic const short nfsv3err_readlink[] = { 2529336Sdfr NFSERR_IO, 2539336Sdfr NFSERR_IO, 2549336Sdfr NFSERR_ACCES, 2559336Sdfr NFSERR_INVAL, 2569336Sdfr NFSERR_STALE, 2579336Sdfr NFSERR_BADHANDLE, 2589336Sdfr NFSERR_NOTSUPP, 2599336Sdfr NFSERR_SERVERFAULT, 2609336Sdfr 0, 2619336Sdfr}; 2629336Sdfr 263129639Srwatsonstatic const short nfsv3err_read[] = { 2649336Sdfr NFSERR_IO, 2659336Sdfr NFSERR_IO, 2669336Sdfr NFSERR_NXIO, 2679336Sdfr NFSERR_ACCES, 2689336Sdfr NFSERR_INVAL, 2699336Sdfr NFSERR_STALE, 2709336Sdfr NFSERR_BADHANDLE, 2719336Sdfr NFSERR_SERVERFAULT, 2729336Sdfr 0, 2739336Sdfr}; 2749336Sdfr 275129639Srwatsonstatic const short nfsv3err_write[] = { 2769336Sdfr NFSERR_IO, 2779336Sdfr NFSERR_IO, 2789336Sdfr NFSERR_ACCES, 2799336Sdfr NFSERR_INVAL, 2809336Sdfr NFSERR_FBIG, 2819336Sdfr NFSERR_NOSPC, 2829336Sdfr NFSERR_ROFS, 2839336Sdfr NFSERR_DQUOT, 2849336Sdfr NFSERR_STALE, 2859336Sdfr NFSERR_BADHANDLE, 2869336Sdfr NFSERR_SERVERFAULT, 2879336Sdfr 0, 2889336Sdfr}; 2899336Sdfr 290129639Srwatsonstatic const short nfsv3err_create[] = { 2919336Sdfr NFSERR_IO, 2929336Sdfr NFSERR_IO, 2939336Sdfr NFSERR_ACCES, 2949336Sdfr NFSERR_EXIST, 2959336Sdfr NFSERR_NOTDIR, 2969336Sdfr NFSERR_NOSPC, 2979336Sdfr NFSERR_ROFS, 2989336Sdfr NFSERR_NAMETOL, 2999336Sdfr NFSERR_DQUOT, 3009336Sdfr NFSERR_STALE, 3019336Sdfr NFSERR_BADHANDLE, 3029336Sdfr NFSERR_NOTSUPP, 3039336Sdfr NFSERR_SERVERFAULT, 3049336Sdfr 0, 3059336Sdfr}; 3069336Sdfr 307129639Srwatsonstatic const short nfsv3err_mkdir[] = { 3089336Sdfr NFSERR_IO, 3099336Sdfr NFSERR_IO, 3109336Sdfr NFSERR_ACCES, 3119336Sdfr NFSERR_EXIST, 3129336Sdfr NFSERR_NOTDIR, 3139336Sdfr NFSERR_NOSPC, 3149336Sdfr NFSERR_ROFS, 3159336Sdfr NFSERR_NAMETOL, 3169336Sdfr NFSERR_DQUOT, 3179336Sdfr NFSERR_STALE, 3189336Sdfr NFSERR_BADHANDLE, 3199336Sdfr NFSERR_NOTSUPP, 3209336Sdfr NFSERR_SERVERFAULT, 3219336Sdfr 0, 3229336Sdfr}; 3239336Sdfr 324129639Srwatsonstatic const short nfsv3err_symlink[] = { 3259336Sdfr NFSERR_IO, 3269336Sdfr NFSERR_IO, 3279336Sdfr NFSERR_ACCES, 3289336Sdfr NFSERR_EXIST, 3299336Sdfr NFSERR_NOTDIR, 3309336Sdfr NFSERR_NOSPC, 3319336Sdfr NFSERR_ROFS, 3329336Sdfr NFSERR_NAMETOL, 3339336Sdfr NFSERR_DQUOT, 3349336Sdfr NFSERR_STALE, 3359336Sdfr NFSERR_BADHANDLE, 3369336Sdfr NFSERR_NOTSUPP, 3379336Sdfr NFSERR_SERVERFAULT, 3389336Sdfr 0, 3399336Sdfr}; 3409336Sdfr 341129639Srwatsonstatic const short nfsv3err_mknod[] = { 3429336Sdfr NFSERR_IO, 3439336Sdfr NFSERR_IO, 3449336Sdfr NFSERR_ACCES, 3459336Sdfr NFSERR_EXIST, 3469336Sdfr NFSERR_NOTDIR, 3479336Sdfr NFSERR_NOSPC, 3489336Sdfr NFSERR_ROFS, 3499336Sdfr NFSERR_NAMETOL, 3509336Sdfr NFSERR_DQUOT, 3519336Sdfr NFSERR_STALE, 3529336Sdfr NFSERR_BADHANDLE, 3539336Sdfr NFSERR_NOTSUPP, 3549336Sdfr NFSERR_SERVERFAULT, 3559336Sdfr NFSERR_BADTYPE, 3569336Sdfr 0, 3579336Sdfr}; 3589336Sdfr 359129639Srwatsonstatic const short nfsv3err_remove[] = { 3609336Sdfr NFSERR_IO, 3619336Sdfr NFSERR_NOENT, 3629336Sdfr NFSERR_IO, 3639336Sdfr NFSERR_ACCES, 3649336Sdfr NFSERR_NOTDIR, 3659336Sdfr NFSERR_ROFS, 3669336Sdfr NFSERR_NAMETOL, 3679336Sdfr NFSERR_STALE, 3689336Sdfr NFSERR_BADHANDLE, 3699336Sdfr NFSERR_SERVERFAULT, 3709336Sdfr 0, 3719336Sdfr}; 3729336Sdfr 373129639Srwatsonstatic const short nfsv3err_rmdir[] = { 3749336Sdfr NFSERR_IO, 3759336Sdfr NFSERR_NOENT, 3769336Sdfr NFSERR_IO, 3779336Sdfr NFSERR_ACCES, 3789336Sdfr NFSERR_EXIST, 3799336Sdfr NFSERR_NOTDIR, 3809336Sdfr NFSERR_INVAL, 3819336Sdfr NFSERR_ROFS, 3829336Sdfr NFSERR_NAMETOL, 3839336Sdfr NFSERR_NOTEMPTY, 3849336Sdfr NFSERR_STALE, 3859336Sdfr NFSERR_BADHANDLE, 3869336Sdfr NFSERR_NOTSUPP, 3879336Sdfr NFSERR_SERVERFAULT, 3889336Sdfr 0, 3899336Sdfr}; 3909336Sdfr 391129639Srwatsonstatic const short nfsv3err_rename[] = { 3929336Sdfr NFSERR_IO, 3939336Sdfr NFSERR_NOENT, 3949336Sdfr NFSERR_IO, 3959336Sdfr NFSERR_ACCES, 3969336Sdfr NFSERR_EXIST, 3979336Sdfr NFSERR_XDEV, 3989336Sdfr NFSERR_NOTDIR, 3999336Sdfr NFSERR_ISDIR, 4009336Sdfr NFSERR_INVAL, 4019336Sdfr NFSERR_NOSPC, 4029336Sdfr NFSERR_ROFS, 4039336Sdfr NFSERR_MLINK, 4049336Sdfr NFSERR_NAMETOL, 4059336Sdfr NFSERR_NOTEMPTY, 4069336Sdfr NFSERR_DQUOT, 4079336Sdfr NFSERR_STALE, 4089336Sdfr NFSERR_BADHANDLE, 4099336Sdfr NFSERR_NOTSUPP, 4109336Sdfr NFSERR_SERVERFAULT, 4119336Sdfr 0, 4129336Sdfr}; 4139336Sdfr 414129639Srwatsonstatic const short nfsv3err_link[] = { 4159336Sdfr NFSERR_IO, 4169336Sdfr NFSERR_IO, 4179336Sdfr NFSERR_ACCES, 4189336Sdfr NFSERR_EXIST, 4199336Sdfr NFSERR_XDEV, 4209336Sdfr NFSERR_NOTDIR, 4219336Sdfr NFSERR_INVAL, 4229336Sdfr NFSERR_NOSPC, 4239336Sdfr NFSERR_ROFS, 4249336Sdfr NFSERR_MLINK, 4259336Sdfr NFSERR_NAMETOL, 4269336Sdfr NFSERR_DQUOT, 4279336Sdfr NFSERR_STALE, 4289336Sdfr NFSERR_BADHANDLE, 4299336Sdfr NFSERR_NOTSUPP, 4309336Sdfr NFSERR_SERVERFAULT, 4319336Sdfr 0, 4329336Sdfr}; 4339336Sdfr 434129639Srwatsonstatic const short nfsv3err_readdir[] = { 4359336Sdfr NFSERR_IO, 4369336Sdfr NFSERR_IO, 4379336Sdfr NFSERR_ACCES, 4389336Sdfr NFSERR_NOTDIR, 4399336Sdfr NFSERR_STALE, 4409336Sdfr NFSERR_BADHANDLE, 4419336Sdfr NFSERR_BAD_COOKIE, 4429336Sdfr NFSERR_TOOSMALL, 4439336Sdfr NFSERR_SERVERFAULT, 4449336Sdfr 0, 4459336Sdfr}; 4469336Sdfr 447129639Srwatsonstatic const short nfsv3err_readdirplus[] = { 4489336Sdfr NFSERR_IO, 4499336Sdfr NFSERR_IO, 4509336Sdfr NFSERR_ACCES, 4519336Sdfr NFSERR_NOTDIR, 4529336Sdfr NFSERR_STALE, 4539336Sdfr NFSERR_BADHANDLE, 4549336Sdfr NFSERR_BAD_COOKIE, 4559336Sdfr NFSERR_NOTSUPP, 4569336Sdfr NFSERR_TOOSMALL, 4579336Sdfr NFSERR_SERVERFAULT, 4589336Sdfr 0, 4599336Sdfr}; 4609336Sdfr 461129639Srwatsonstatic const short nfsv3err_fsstat[] = { 4629336Sdfr NFSERR_IO, 4639336Sdfr NFSERR_IO, 4649336Sdfr NFSERR_STALE, 4659336Sdfr NFSERR_BADHANDLE, 4669336Sdfr NFSERR_SERVERFAULT, 4679336Sdfr 0, 4689336Sdfr}; 4699336Sdfr 470129639Srwatsonstatic const short nfsv3err_fsinfo[] = { 4719336Sdfr NFSERR_STALE, 4729336Sdfr NFSERR_STALE, 4739336Sdfr NFSERR_BADHANDLE, 4749336Sdfr NFSERR_SERVERFAULT, 4759336Sdfr 0, 4769336Sdfr}; 4779336Sdfr 478129639Srwatsonstatic const short nfsv3err_pathconf[] = { 4799336Sdfr NFSERR_STALE, 4809336Sdfr NFSERR_STALE, 4819336Sdfr NFSERR_BADHANDLE, 4829336Sdfr NFSERR_SERVERFAULT, 4839336Sdfr 0, 4849336Sdfr}; 4859336Sdfr 486129639Srwatsonstatic const short nfsv3err_commit[] = { 4879336Sdfr NFSERR_IO, 4889336Sdfr NFSERR_IO, 4899336Sdfr NFSERR_STALE, 4909336Sdfr NFSERR_BADHANDLE, 4919336Sdfr NFSERR_SERVERFAULT, 4929336Sdfr 0, 4939336Sdfr}; 4949336Sdfr 495129639Srwatsonstatic const short *nfsrv_v3errmap[] = { 4969336Sdfr nfsv3err_null, 4979336Sdfr nfsv3err_getattr, 4989336Sdfr nfsv3err_setattr, 4999336Sdfr nfsv3err_lookup, 5009336Sdfr nfsv3err_access, 5019336Sdfr nfsv3err_readlink, 5029336Sdfr nfsv3err_read, 5039336Sdfr nfsv3err_write, 5049336Sdfr nfsv3err_create, 5059336Sdfr nfsv3err_mkdir, 5069336Sdfr nfsv3err_symlink, 5079336Sdfr nfsv3err_mknod, 5089336Sdfr nfsv3err_remove, 5099336Sdfr nfsv3err_rmdir, 5109336Sdfr nfsv3err_rename, 5119336Sdfr nfsv3err_link, 5129336Sdfr nfsv3err_readdir, 5139336Sdfr nfsv3err_readdirplus, 5149336Sdfr nfsv3err_fsstat, 5159336Sdfr nfsv3err_fsinfo, 5169336Sdfr nfsv3err_pathconf, 5179336Sdfr nfsv3err_commit, 5189336Sdfr}; 5199336Sdfr 5201541Srgrimes/* 5211541Srgrimes * Called once to initialize data structures... 5221541Srgrimes */ 52383651Speterstatic int 52483700Speternfsrv_modevent(module_t mod, int type, void *data) 5251541Srgrimes{ 526168268Sjhb static int registered; 527132199Sphk int error = 0; 5281541Srgrimes 52983700Speter switch (type) { 53083700Speter case MOD_LOAD: 531129639Srwatson mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF); 53289094Smsmith nfsrv_rpc_vers = txdr_unsigned(RPC_VER2); 53389094Smsmith nfsrv_rpc_call = txdr_unsigned(RPC_CALL); 53489094Smsmith nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY); 53589094Smsmith nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 53689094Smsmith nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 53789094Smsmith nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 53889094Smsmith nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR); 53989094Smsmith nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 54089094Smsmith nfsrv_nfs_prog = txdr_unsigned(NFS_PROG); 54189094Smsmith nfsrv_nfs_true = txdr_unsigned(TRUE); 54289094Smsmith nfsrv_nfs_false = txdr_unsigned(FALSE); 54389094Smsmith nfsrv_nfs_xdrneg1 = txdr_unsigned(-1); 54489094Smsmith nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 54589094Smsmith if (nfsrv_ticks < 1) 54689094Smsmith nfsrv_ticks = 1; 54783651Speter 548129639Srwatson nfsrv_initcache(); /* Init the server request cache */ 549129639Srwatson NFSD_LOCK(); 55083700Speter nfsrv_init(0); /* Init server data structures */ 551171613Srwatson callout_init(&nfsrv_callout, CALLOUT_MPSAFE); 552129639Srwatson NFSD_UNLOCK(); 55383700Speter nfsrv_timer(0); 5541541Srgrimes 555168268Sjhb error = syscall_register(&nfssvc_offset, &nfssvc_sysent, 556168268Sjhb &nfssvc_prev_sysent); 557168268Sjhb if (error) 558168268Sjhb break; 559168268Sjhb registered = 1; 56083700Speter break; 5612997Swollman 562132199Sphk case MOD_UNLOAD: 563129902Sbmilekic if (nfsrv_numnfsd != 0) { 564132199Sphk error = EBUSY; 565132199Sphk break; 566129902Sbmilekic } 56783700Speter 568168268Sjhb if (registered) 569168268Sjhb syscall_deregister(&nfssvc_offset, &nfssvc_prev_sysent); 570160881Sjhb callout_drain(&nfsrv_callout); 571160881Sjhb nfsrv_destroycache(); /* Free the server request cache */ 572129639Srwatson mtx_destroy(&nfsd_mtx); 57383700Speter break; 574132199Sphk default: 575132199Sphk error = EOPNOTSUPP; 576132199Sphk break; 57783700Speter } 578132199Sphk return error; 5791541Srgrimes} 58083700Speterstatic moduledata_t nfsserver_mod = { 58183700Speter "nfsserver", 58283700Speter nfsrv_modevent, 58383700Speter NULL, 58483700Speter}; 58583700SpeterDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY); 5861541Srgrimes 58783700Speter/* So that loader and kldload(2) can find us, wherever we are.. */ 58883700SpeterMODULE_VERSION(nfsserver, 1); 58938894Sbde 5901541Srgrimes/* 59127446Sdfr * Set up nameidata for a lookup() call and do it. 59227446Sdfr * 59327446Sdfr * If pubflag is set, this call is done for a lookup operation on the 59427446Sdfr * public filehandle. In that case we allow crossing mountpoints and 59527446Sdfr * absolute pathnames. However, the caller is expected to check that 59627446Sdfr * the lookup result is within the public fs, and deny access if 59727446Sdfr * it is not. 59848125Sjulian * 59948125Sjulian * nfs_namei() clears out garbage fields that namei() might leave garbage. 60048125Sjulian * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 60148125Sjulian * error occurs but the parent was not requested. 60248125Sjulian * 60383651Speter * dirp may be set whether an error is returned or not, and must be 60448125Sjulian * released by the caller. 6051541Srgrimes */ 6061549Srgrimesint 60783651Speternfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, 60883651Speter struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, 609115301Struckman caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp, 610115301Struckman int *retdirattr_retp, struct thread *td, int pubflag) 6111541Srgrimes{ 61283651Speter int i, rem; 61383651Speter struct mbuf *md; 61483651Speter char *fromcp, *tocp, *cp; 61527446Sdfr struct iovec aiov; 61627446Sdfr struct uio auio; 6171541Srgrimes struct vnode *dp; 61827446Sdfr int error, rdonly, linklen; 6191541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 620115301Struckman int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0; 621167665Sjeff int dvfslocked; 622167665Sjeff int vfslocked; 6231541Srgrimes 624167665Sjeff vfslocked = 0; 625167665Sjeff dvfslocked = 0; 62699797Sdillon *retdirp = NULL; 627105481Srwatson cnp->cn_flags |= NOMACCHECK; 628111119Simp cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 62929653Sdyson 6301541Srgrimes /* 6311541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 6321541Srgrimes * and set the various ndp fields appropriately. 6331541Srgrimes */ 6341541Srgrimes fromcp = *dposp; 6351541Srgrimes tocp = cnp->cn_pnbuf; 6361541Srgrimes md = *mdp; 6371541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 6381541Srgrimes for (i = 0; i < len; i++) { 6391541Srgrimes while (rem == 0) { 6401541Srgrimes md = md->m_next; 6411541Srgrimes if (md == NULL) { 6421541Srgrimes error = EBADRPC; 643167665Sjeff goto out; 6441541Srgrimes } 6451541Srgrimes fromcp = mtod(md, caddr_t); 6461541Srgrimes rem = md->m_len; 6471541Srgrimes } 64827446Sdfr if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 6499336Sdfr error = EACCES; 650167665Sjeff goto out; 6511541Srgrimes } 6521541Srgrimes *tocp++ = *fromcp++; 6531541Srgrimes rem--; 6541541Srgrimes } 6551541Srgrimes *tocp = '\0'; 6561541Srgrimes *mdp = md; 6571541Srgrimes *dposp = fromcp; 6581541Srgrimes len = nfsm_rndup(len)-len; 6591541Srgrimes if (len > 0) { 6601541Srgrimes if (rem >= len) 6611541Srgrimes *dposp += len; 66227609Sdfr else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 663167665Sjeff goto out; 6641541Srgrimes } 66527446Sdfr 6661541Srgrimes /* 6671541Srgrimes * Extract and set starting directory. 6681541Srgrimes */ 669167665Sjeff error = nfsrv_fhtovp(fhp, FALSE, &dp, &dvfslocked, 670167665Sjeff ndp->ni_cnd.cn_cred, slp, nam, &rdonly, pubflag); 67127446Sdfr if (error) 6721541Srgrimes goto out; 673167665Sjeff vfslocked = VFS_LOCK_GIANT(dp->v_mount); 6741541Srgrimes if (dp->v_type != VDIR) { 67517761Sdyson vrele(dp); 6761541Srgrimes error = ENOTDIR; 6771541Srgrimes goto out; 6781541Srgrimes } 67927446Sdfr 68027446Sdfr if (rdonly) 68127446Sdfr cnp->cn_flags |= RDONLY; 68227446Sdfr 68348125Sjulian /* 68483651Speter * Set return directory. Reference to dp is implicitly transfered 68548125Sjulian * to the returned pointer 68648125Sjulian */ 68727609Sdfr *retdirp = dp; 688115301Struckman if (v3) { 689175202Sattilio vn_lock(dp, LK_EXCLUSIVE | LK_RETRY); 690115301Struckman *retdirattr_retp = VOP_GETATTR(dp, retdirattrp, 691182371Sattilio ndp->ni_cnd.cn_cred); 692175294Sattilio VOP_UNLOCK(dp, 0); 693115301Struckman } 69427609Sdfr 69527446Sdfr if (pubflag) { 69627446Sdfr /* 69727446Sdfr * Oh joy. For WebNFS, handle those pesky '%' escapes, 69827446Sdfr * and the 'native path' indicator. 69927446Sdfr */ 700111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 70127446Sdfr fromcp = cnp->cn_pnbuf; 70227446Sdfr tocp = cp; 70327446Sdfr if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 70427446Sdfr switch ((unsigned char)*fromcp) { 70527446Sdfr case WEBNFS_NATIVE_CHAR: 70627446Sdfr /* 70727446Sdfr * 'Native' path for us is the same 70827446Sdfr * as a path according to the NFS spec, 70927446Sdfr * just skip the escape char. 71027446Sdfr */ 71127446Sdfr fromcp++; 71227446Sdfr break; 71327446Sdfr /* 71427446Sdfr * More may be added in the future, range 0x80-0xff 71527446Sdfr */ 71627446Sdfr default: 71727446Sdfr error = EIO; 71892783Sjeff uma_zfree(namei_zone, cp); 71927446Sdfr goto out; 72027446Sdfr } 72127446Sdfr } 72227446Sdfr /* 72327446Sdfr * Translate the '%' escapes, URL-style. 72427446Sdfr */ 72527446Sdfr while (*fromcp != '\0') { 72627446Sdfr if (*fromcp == WEBNFS_ESC_CHAR) { 72727446Sdfr if (fromcp[1] != '\0' && fromcp[2] != '\0') { 72827446Sdfr fromcp++; 72927446Sdfr *tocp++ = HEXSTRTOI(fromcp); 73027446Sdfr fromcp += 2; 73127446Sdfr continue; 73227446Sdfr } else { 73327446Sdfr error = ENOENT; 73492783Sjeff uma_zfree(namei_zone, cp); 73527446Sdfr goto out; 73627446Sdfr } 73727446Sdfr } else 73827446Sdfr *tocp++ = *fromcp++; 73927446Sdfr } 74027446Sdfr *tocp = '\0'; 74192783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 74227446Sdfr cnp->cn_pnbuf = cp; 74327446Sdfr } 74427446Sdfr 74527446Sdfr ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 74627446Sdfr ndp->ni_segflg = UIO_SYSSPACE; 74727446Sdfr 74827446Sdfr if (pubflag) { 74927446Sdfr ndp->ni_rootdir = rootvnode; 75027446Sdfr ndp->ni_loopcnt = 0; 751167665Sjeff if (cnp->cn_pnbuf[0] == '/') { 752167665Sjeff int tvfslocked; 753167665Sjeff 754167665Sjeff tvfslocked = VFS_LOCK_GIANT(rootvnode->v_mount); 755167665Sjeff VFS_UNLOCK_GIANT(vfslocked); 75627446Sdfr dp = rootvnode; 757167665Sjeff vfslocked = tvfslocked; 758167665Sjeff } 75927446Sdfr } else { 76027609Sdfr cnp->cn_flags |= NOCROSSMOUNT; 76127446Sdfr } 76227446Sdfr 76348125Sjulian /* 76448125Sjulian * Initialize for scan, set ni_startdir and bump ref on dp again 765123608Sjhb * because lookup() will dereference ni_startdir. 76648125Sjulian */ 76748125Sjulian 76883366Sjulian cnp->cn_thread = td; 7699336Sdfr VREF(dp); 77048125Sjulian ndp->ni_startdir = dp; 77127446Sdfr 772115301Struckman if (!lockleaf) 773115301Struckman cnp->cn_flags |= LOCKLEAF; 77448125Sjulian for (;;) { 77548125Sjulian cnp->cn_nameptr = cnp->cn_pnbuf; 77648125Sjulian /* 77748125Sjulian * Call lookup() to do the real work. If an error occurs, 77848125Sjulian * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 77948125Sjulian * we do not have to dereference anything before returning. 78048125Sjulian * In either case ni_startdir will be dereferenced and NULLed 78148125Sjulian * out. 78248125Sjulian */ 783167665Sjeff if (vfslocked) 784167665Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 78548125Sjulian error = lookup(ndp); 786167665Sjeff vfslocked = (ndp->ni_cnd.cn_flags & GIANTHELD) != 0; 787167665Sjeff ndp->ni_cnd.cn_flags &= ~GIANTHELD; 78848125Sjulian if (error) 78948125Sjulian break; 79048125Sjulian 79148125Sjulian /* 79283651Speter * Check for encountering a symbolic link. Trivial 79348125Sjulian * termination occurs if no symlink encountered. 79448125Sjulian * Note: zfree is safe because error is 0, so we will 79548125Sjulian * not zfree it again when we break. 79648125Sjulian */ 79748125Sjulian if ((cnp->cn_flags & ISSYMLINK) == 0) { 79848125Sjulian if (cnp->cn_flags & (SAVENAME | SAVESTART)) 79948125Sjulian cnp->cn_flags |= HASBUF; 80048125Sjulian else 80192783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 802115301Struckman if (ndp->ni_vp && !lockleaf) 803175294Sattilio VOP_UNLOCK(ndp->ni_vp, 0); 80448125Sjulian break; 80527446Sdfr } 80648125Sjulian 80748125Sjulian /* 80848125Sjulian * Validate symlink 80948125Sjulian */ 8101541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 811175294Sattilio VOP_UNLOCK(ndp->ni_dvp, 0); 81227446Sdfr if (!pubflag) { 81327446Sdfr error = EINVAL; 81448125Sjulian goto badlink2; 81527446Sdfr } 81627446Sdfr 81727446Sdfr if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 81827446Sdfr error = ELOOP; 81948125Sjulian goto badlink2; 82027446Sdfr } 82127609Sdfr if (ndp->ni_pathlen > 1) 822111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 8231541Srgrimes else 82427446Sdfr cp = cnp->cn_pnbuf; 82527446Sdfr aiov.iov_base = cp; 82627446Sdfr aiov.iov_len = MAXPATHLEN; 82727446Sdfr auio.uio_iov = &aiov; 82827446Sdfr auio.uio_iovcnt = 1; 82927446Sdfr auio.uio_offset = 0; 83027446Sdfr auio.uio_rw = UIO_READ; 83127446Sdfr auio.uio_segflg = UIO_SYSSPACE; 83299797Sdillon auio.uio_td = NULL; 83327446Sdfr auio.uio_resid = MAXPATHLEN; 83427446Sdfr error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 83527446Sdfr if (error) { 83648125Sjulian badlink1: 83727446Sdfr if (ndp->ni_pathlen > 1) 83892783Sjeff uma_zfree(namei_zone, cp); 83948125Sjulian badlink2: 840155160Sjeff vput(ndp->ni_vp); 84148125Sjulian vrele(ndp->ni_dvp); 84227446Sdfr break; 84327446Sdfr } 84427446Sdfr linklen = MAXPATHLEN - auio.uio_resid; 84527446Sdfr if (linklen == 0) { 84627446Sdfr error = ENOENT; 84748125Sjulian goto badlink1; 84827446Sdfr } 84927446Sdfr if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 85027446Sdfr error = ENAMETOOLONG; 85148125Sjulian goto badlink1; 85227446Sdfr } 85348125Sjulian 85448125Sjulian /* 85548125Sjulian * Adjust or replace path 85648125Sjulian */ 85727446Sdfr if (ndp->ni_pathlen > 1) { 85827446Sdfr bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 85992783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 86027446Sdfr cnp->cn_pnbuf = cp; 86127446Sdfr } else 86227446Sdfr cnp->cn_pnbuf[linklen] = '\0'; 86327446Sdfr ndp->ni_pathlen += linklen; 86448125Sjulian 86527446Sdfr /* 86683651Speter * Cleanup refs for next loop and check if root directory 86783651Speter * should replace current directory. Normally ni_dvp 86848125Sjulian * becomes the new base directory and is cleaned up when 86948125Sjulian * we loop. Explicitly null pointers after invalidation 87048125Sjulian * to clarify operation. 87127446Sdfr */ 87248125Sjulian vput(ndp->ni_vp); 87348125Sjulian ndp->ni_vp = NULL; 87448125Sjulian 87527446Sdfr if (cnp->cn_pnbuf[0] == '/') { 87648125Sjulian vrele(ndp->ni_dvp); 87748125Sjulian ndp->ni_dvp = ndp->ni_rootdir; 87848125Sjulian VREF(ndp->ni_dvp); 87927446Sdfr } 88048125Sjulian ndp->ni_startdir = ndp->ni_dvp; 88148125Sjulian ndp->ni_dvp = NULL; 8821541Srgrimes } 883115301Struckman if (!lockleaf) 884115301Struckman cnp->cn_flags &= ~LOCKLEAF; 885159268Skib if (cnp->cn_flags & GIANTHELD) { 886159268Skib mtx_unlock(&Giant); 887159268Skib cnp->cn_flags &= ~GIANTHELD; 888159268Skib } 88948125Sjulian 89048125Sjulian /* 89148125Sjulian * nfs_namei() guarentees that fields will not contain garbage 89248125Sjulian * whether an error occurs or not. This allows the caller to track 89348125Sjulian * cleanup state trivially. 89448125Sjulian */ 8951541Srgrimesout: 89648125Sjulian if (error) { 89792783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 89848125Sjulian ndp->ni_vp = NULL; 89948125Sjulian ndp->ni_dvp = NULL; 90048125Sjulian ndp->ni_startdir = NULL; 90148125Sjulian cnp->cn_flags &= ~HASBUF; 902167665Sjeff VFS_UNLOCK_GIANT(vfslocked); 903167665Sjeff vfslocked = 0; 90448125Sjulian } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 90548125Sjulian ndp->ni_dvp = NULL; 90648125Sjulian } 907167665Sjeff /* 908167665Sjeff * This differs from normal namei() in that even on failure we may 909167665Sjeff * return with Giant held due to the dirp return. Make sure we only 910167665Sjeff * have not recursed however. The calling code only expects to drop 911167665Sjeff * one acquire. 912167665Sjeff */ 913167665Sjeff if (vfslocked || dvfslocked) 914167665Sjeff ndp->ni_cnd.cn_flags |= GIANTHELD; 915167665Sjeff if (vfslocked && dvfslocked) 916167665Sjeff VFS_UNLOCK_GIANT(vfslocked); 9171541Srgrimes return (error); 9181541Srgrimes} 9191541Srgrimes 9201541Srgrimes/* 9211541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 9221541Srgrimes * boundary and only trims off the back end 9231541Srgrimes */ 9241541Srgrimesvoid 92583651Speternfsm_adj(struct mbuf *mp, int len, int nul) 9261541Srgrimes{ 92783651Speter struct mbuf *m; 92883651Speter int count, i; 92983651Speter char *cp; 9301541Srgrimes 9311541Srgrimes /* 9321541Srgrimes * Trim from tail. Scan the mbuf chain, 9331541Srgrimes * calculating its length and finding the last mbuf. 9341541Srgrimes * If the adjustment only affects this mbuf, then just 9351541Srgrimes * adjust and return. Otherwise, rescan and truncate 9361541Srgrimes * after the remaining size. 9371541Srgrimes */ 9381541Srgrimes count = 0; 9391541Srgrimes m = mp; 9401541Srgrimes for (;;) { 9411541Srgrimes count += m->m_len; 94299797Sdillon if (m->m_next == NULL) 9431541Srgrimes break; 9441541Srgrimes m = m->m_next; 9451541Srgrimes } 9461541Srgrimes if (m->m_len > len) { 9471541Srgrimes m->m_len -= len; 9481541Srgrimes if (nul > 0) { 9491541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 9501541Srgrimes for (i = 0; i < nul; i++) 9511541Srgrimes *cp++ = '\0'; 9521541Srgrimes } 9531541Srgrimes return; 9541541Srgrimes } 9551541Srgrimes count -= len; 9561541Srgrimes if (count < 0) 9571541Srgrimes count = 0; 9581541Srgrimes /* 9591541Srgrimes * Correct length for chain is "count". 9601541Srgrimes * Find the mbuf with last data, adjust its length, 9611541Srgrimes * and toss data from remaining mbufs on chain. 9621541Srgrimes */ 9631541Srgrimes for (m = mp; m; m = m->m_next) { 9641541Srgrimes if (m->m_len >= count) { 9651541Srgrimes m->m_len = count; 9661541Srgrimes if (nul > 0) { 9671541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 9681541Srgrimes for (i = 0; i < nul; i++) 9691541Srgrimes *cp++ = '\0'; 9701541Srgrimes } 971144246Ssam if (m->m_next != NULL) { 972144246Ssam m_freem(m->m_next); 973144246Ssam m->m_next = NULL; 974144246Ssam } 9751541Srgrimes break; 9761541Srgrimes } 9771541Srgrimes count -= m->m_len; 9781541Srgrimes } 9791541Srgrimes} 9801541Srgrimes 9811541Srgrimes/* 9829336Sdfr * Make these functions instead of macros, so that the kernel text size 9839336Sdfr * doesn't get too big... 9849336Sdfr */ 9859336Sdfrvoid 98683651Speternfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 98783651Speter struct vattr *before_vap, int after_ret, struct vattr *after_vap, 98883651Speter struct mbuf **mbp, char **bposp) 9899336Sdfr{ 99083651Speter struct mbuf *mb = *mbp; 99183651Speter char *bpos = *bposp; 99283651Speter u_int32_t *tl; 9939336Sdfr 9949336Sdfr if (before_ret) { 99584002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 99689094Smsmith *tl = nfsrv_nfs_false; 9979336Sdfr } else { 99884002Speter tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 99989094Smsmith *tl++ = nfsrv_nfs_true; 100047751Speter txdr_hyper(before_vap->va_size, tl); 10019336Sdfr tl += 2; 10029336Sdfr txdr_nfsv3time(&(before_vap->va_mtime), tl); 10039336Sdfr tl += 2; 10049336Sdfr txdr_nfsv3time(&(before_vap->va_ctime), tl); 10059336Sdfr } 10069336Sdfr *bposp = bpos; 10079336Sdfr *mbp = mb; 10089336Sdfr nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 10099336Sdfr} 10109336Sdfr 10119336Sdfrvoid 101283651Speternfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 101383651Speter struct vattr *after_vap, struct mbuf **mbp, char **bposp) 10149336Sdfr{ 101583651Speter struct mbuf *mb = *mbp; 101683651Speter char *bpos = *bposp; 101783651Speter u_int32_t *tl; 101883651Speter struct nfs_fattr *fp; 10199336Sdfr 10209336Sdfr if (after_ret) { 102184002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 102289094Smsmith *tl = nfsrv_nfs_false; 10239336Sdfr } else { 102484002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 102589094Smsmith *tl++ = nfsrv_nfs_true; 10269336Sdfr fp = (struct nfs_fattr *)tl; 10279336Sdfr nfsm_srvfattr(nfsd, after_vap, fp); 10289336Sdfr } 10299336Sdfr *mbp = mb; 10309336Sdfr *bposp = bpos; 10319336Sdfr} 10329336Sdfr 10339336Sdfrvoid 103483651Speternfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 103583651Speter struct nfs_fattr *fp) 10369336Sdfr{ 10379336Sdfr 10389336Sdfr fp->fa_nlink = txdr_unsigned(vap->va_nlink); 10399336Sdfr fp->fa_uid = txdr_unsigned(vap->va_uid); 10409336Sdfr fp->fa_gid = txdr_unsigned(vap->va_gid); 10419336Sdfr if (nfsd->nd_flag & ND_NFSV3) { 10429336Sdfr fp->fa_type = vtonfsv3_type(vap->va_type); 10439336Sdfr fp->fa_mode = vtonfsv3_mode(vap->va_mode); 104447751Speter txdr_hyper(vap->va_size, &fp->fa3_size); 104547751Speter txdr_hyper(vap->va_bytes, &fp->fa3_used); 104647028Sphk fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 104747028Sphk fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 10489336Sdfr fp->fa3_fsid.nfsuquad[0] = 0; 10499336Sdfr fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 10509336Sdfr fp->fa3_fileid.nfsuquad[0] = 0; 10519336Sdfr fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 10529336Sdfr txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 10539336Sdfr txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 10549336Sdfr txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 10559336Sdfr } else { 10569336Sdfr fp->fa_type = vtonfsv2_type(vap->va_type); 10579336Sdfr fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 10589336Sdfr fp->fa2_size = txdr_unsigned(vap->va_size); 10599336Sdfr fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 10609336Sdfr if (vap->va_type == VFIFO) 10619336Sdfr fp->fa2_rdev = 0xffffffff; 10629336Sdfr else 10639336Sdfr fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 10649336Sdfr fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 10659336Sdfr fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 10669336Sdfr fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 10679336Sdfr txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 10689336Sdfr txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 10699336Sdfr txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 10709336Sdfr } 10719336Sdfr} 10729336Sdfr 10739336Sdfr/* 10741541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 10751541Srgrimes * - look up fsid in mount list (if not found ret error) 10761541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 10771541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 10781541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 10791541Srgrimes */ 10801549Srgrimesint 1081167665Sjeffnfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, int *vfslockedp, 108283651Speter struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 108383651Speter int *rdonlyp, int pubflag) 10841541Srgrimes{ 108583651Speter struct mount *mp; 108683651Speter int i; 10871541Srgrimes struct ucred *credanon; 10881541Srgrimes int error, exflags; 108936534Speter#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 109036534Speter struct sockaddr_int *saddr; 109136534Speter#endif 1092167665Sjeff int vfslocked; 10931541Srgrimes 1094167665Sjeff *vfslockedp = 0; 109599797Sdillon *vpp = NULL; 109627446Sdfr 109727446Sdfr if (nfs_ispublicfh(fhp)) { 109827446Sdfr if (!pubflag || !nfs_pub.np_valid) 109927446Sdfr return (ESTALE); 110027446Sdfr fhp = &nfs_pub.np_handle; 110127446Sdfr } 110227446Sdfr 110322521Sdyson mp = vfs_getvfs(&fhp->fh_fsid); 11043305Sphk if (!mp) 11051541Srgrimes return (ESTALE); 1106157325Sjeff vfslocked = VFS_LOCK_GIANT(mp); 110751138Salfred error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 11083305Sphk if (error) 1109129639Srwatson goto out; 111051138Salfred error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 111151138Salfred if (error) 1112129639Srwatson goto out; 111336534Speter#ifdef MNT_EXNORESPORT 111436534Speter if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 111536534Speter saddr = (struct sockaddr_in *)nam; 1116100134Salfred if ((saddr->sin_family == AF_INET || 1117100134Salfred saddr->sin_family == AF_INET6) && 1118100134Salfred /* same code for INET and INET6: sin*_port at same offet */ 111936534Speter ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 112036534Speter vput(*vpp); 112154485Sdillon *vpp = NULL; 1122129639Srwatson error = NFSERR_AUTHERR | AUTH_TOOWEAK; 112336534Speter } 112436534Speter } 112536534Speter#endif 11261541Srgrimes /* 11271541Srgrimes * Check/setup credentials. 11281541Srgrimes */ 112983651Speter if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 11301541Srgrimes cred->cr_uid = credanon->cr_uid; 11311541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 11321541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 11333664Sphk cred->cr_ngroups = i; 11341541Srgrimes } 11351541Srgrimes if (exflags & MNT_EXRDONLY) 11361541Srgrimes *rdonlyp = 1; 11371541Srgrimes else 11381541Srgrimes *rdonlyp = 0; 11397969Sdyson 11401541Srgrimes if (!lockflag) 1141175294Sattilio VOP_UNLOCK(*vpp, 0); 1142129639Srwatsonout: 1143157325Sjeff vfs_rel(mp); 1144167665Sjeff if (error) { 1145167665Sjeff VFS_UNLOCK_GIANT(vfslocked); 1146167665Sjeff } else 1147167665Sjeff *vfslockedp = vfslocked; 1148164585Srwatson return (error); 1149164585Srwatson} 1150164585Srwatson 1151164585Srwatson 115227446Sdfr/* 115327446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this 115427446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 115527446Sdfr * transformed this to all zeroes in both cases, so check for it. 115627446Sdfr */ 115727446Sdfrint 115883651Speternfs_ispublicfh(fhandle_t *fhp) 115927446Sdfr{ 116027446Sdfr char *cp = (char *)fhp; 116127446Sdfr int i; 116227446Sdfr 1163129639Srwatson NFSD_LOCK_DONTCARE(); 1164129639Srwatson 116527446Sdfr for (i = 0; i < NFSX_V3FH; i++) 116627446Sdfr if (*cp++ != 0) 116727446Sdfr return (FALSE); 116827446Sdfr return (TRUE); 116927446Sdfr} 117083651Speter 11711541Srgrimes/* 11721541Srgrimes * This function compares two net addresses by family and returns TRUE 11731541Srgrimes * if they are the same host. 11741541Srgrimes * If there is any doubt, return FALSE. 11751541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 11761541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 11771541Srgrimes */ 11781549Srgrimesint 117983651Speternetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) 11801541Srgrimes{ 118183651Speter struct sockaddr_in *inetaddr; 11821541Srgrimes 1183129639Srwatson NFSD_LOCK_DONTCARE(); 1184129639Srwatson 11851541Srgrimes switch (family) { 11861541Srgrimes case AF_INET: 118728270Swollman inetaddr = (struct sockaddr_in *)nam; 11881541Srgrimes if (inetaddr->sin_family == AF_INET && 11891541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 11901541Srgrimes return (1); 11911541Srgrimes break; 1192100134Salfred#ifdef INET6 1193100134Salfred case AF_INET6: 1194100134Salfred { 1195100134Salfred register struct sockaddr_in6 *inet6addr1, *inet6addr2; 1196100134Salfred 1197100134Salfred inet6addr1 = (struct sockaddr_in6 *)nam; 1198100134Salfred inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam; 1199100134Salfred /* XXX - should test sin6_scope_id ? */ 1200100134Salfred if (inet6addr1->sin6_family == AF_INET6 && 1201100134Salfred IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 1202100134Salfred &inet6addr2->sin6_addr)) 1203100134Salfred return (1); 1204100134Salfred break; 1205100134Salfred } 1206100134Salfred#endif 12071541Srgrimes default: 12081541Srgrimes break; 12091541Srgrimes }; 12101541Srgrimes return (0); 12111541Srgrimes} 12125455Sdg 12139336Sdfr/* 12149336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error 12159336Sdfr * numbers not specified for the associated procedure. 12169336Sdfr */ 12175455Sdgint 121883651Speternfsrv_errmap(struct nfsrv_descript *nd, int err) 12199336Sdfr{ 1220129639Srwatson const short *defaulterrp, *errp; 1221102236Sphk int e; 12229336Sdfr 1223129639Srwatson 12249336Sdfr if (nd->nd_flag & ND_NFSV3) { 12259336Sdfr if (nd->nd_procnum <= NFSPROC_COMMIT) { 12269336Sdfr errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 12279336Sdfr while (*++errp) { 12289336Sdfr if (*errp == err) 12299336Sdfr return (err); 12309336Sdfr else if (*errp > err) 12319336Sdfr break; 12329336Sdfr } 12339336Sdfr return ((int)*defaulterrp); 12349336Sdfr } else 12359336Sdfr return (err & 0xffff); 12369336Sdfr } 1237102236Sphk e = 0; 12389336Sdfr if (err <= ELAST) 1239102236Sphk e = nfsrv_v2errmap[err - 1]; 1240102236Sphk if (e != 0) 1241102236Sphk return (e); 12429336Sdfr return (NFSERR_IO); 12439336Sdfr} 12449336Sdfr 124536503Speter/* 124636503Speter * Sort the group list in increasing numerical order. 124736503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 124836503Speter * that used to be here.) 124936503Speter */ 125036503Spetervoid 125183651Speternfsrvw_sort(gid_t *list, int num) 125236503Speter{ 125383651Speter int i, j; 125436503Speter gid_t v; 125536503Speter 125636503Speter /* Insertion sort. */ 125736503Speter for (i = 1; i < num; i++) { 125836503Speter v = list[i]; 125936503Speter /* find correct slot for value v, moving others up */ 126036503Speter for (j = i; --j >= 0 && v < list[j];) 126136503Speter list[j + 1] = list[j]; 126236503Speter list[j + 1] = v; 126336503Speter } 126436503Speter} 126536503Speter 126636503Speter/* 126783651Speter * Helper functions for macros. 126883651Speter */ 126983651Speter 127083651Spetervoid 127188091Siedowsenfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos) 127283651Speter{ 127388091Siedowse u_int32_t *tl; 127483651Speter 127583651Speter if (v3) { 127688091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 127788091Siedowse *tl++ = txdr_unsigned(NFSX_V3FH); 127888091Siedowse bcopy(f, tl, NFSX_V3FH); 127983651Speter } else { 128088091Siedowse tl = nfsm_build_xx(NFSX_V2FH, mb, bpos); 128188091Siedowse bcopy(f, tl, NFSX_V2FH); 128283651Speter } 128383651Speter} 128483651Speter 128583651Spetervoid 128688091Siedowsenfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos) 128783651Speter{ 128888091Siedowse u_int32_t *tl; 128984002Speter 129088091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 129189094Smsmith *tl++ = nfsrv_nfs_true; 129288091Siedowse *tl++ = txdr_unsigned(NFSX_V3FH); 129388091Siedowse bcopy(f, tl, NFSX_V3FH); 129483651Speter} 129583651Speter 129683651Speterint 129788091Siedowsenfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 129883651Speter{ 129988091Siedowse u_int32_t *tl; 130083651Speter 1301140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 130288091Siedowse if (tl == NULL) 130384057Speter return EBADRPC; 130488091Siedowse *s = fxdr_unsigned(int32_t, *tl); 130583651Speter if (*s > m || *s <= 0) 130683651Speter return EBADRPC; 130783651Speter return 0; 130883651Speter} 130983651Speter 131083651Speterint 1311106264Sjeffnfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 131283651Speter{ 131388091Siedowse u_int32_t *tl; 131483651Speter 1315129639Srwatson NFSD_LOCK_DONTCARE(); 1316129639Srwatson 1317140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 131888091Siedowse if (tl == NULL) 131984057Speter return EBADRPC; 132088091Siedowse *s = fxdr_unsigned(int32_t, *tl); 1321106264Sjeff if (*s > m) 132283651Speter return NFSERR_NAMETOL; 132383651Speter if (*s <= 0) 132483651Speter return EBADRPC; 132583651Speter return 0; 132683651Speter} 132783651Speter 1328165739Shrsint 1329165739Shrsnfsm_srvnamesiz0_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 1330165739Shrs{ 1331165739Shrs u_int32_t *tl; 1332165739Shrs 1333165739Shrs tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 1334165739Shrs if (tl == NULL) 1335165739Shrs return EBADRPC; 1336165739Shrs *s = fxdr_unsigned(int32_t, *tl); 1337165739Shrs if (*s > m) 1338165739Shrs return NFSERR_NAMETOL; 1339165739Shrs if (*s < 0) 1340165739Shrs return EBADRPC; 1341165739Shrs return 0; 1342165739Shrs} 1343165739Shrs 134483651Spetervoid 134583651Speternfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp, 1346167665Sjeff char **bp, char **be, caddr_t bpos) 134783651Speter{ 134883651Speter struct mbuf *nmp; 134983651Speter 1350167665Sjeff NFSD_UNLOCK_ASSERT(); 1351129639Srwatson 135283651Speter if (*bp >= *be) { 135383651Speter if (*mp == mb) 135483651Speter (*mp)->m_len += *bp - bpos; 1355177599Sru MGET(nmp, M_WAIT, MT_DATA); 1356177599Sru MCLGET(nmp, M_WAIT); 135783651Speter nmp->m_len = NFSMSIZ(nmp); 135883651Speter (*mp)->m_next = nmp; 135983651Speter *mp = nmp; 136083651Speter *bp = mtod(*mp, caddr_t); 136183651Speter *be = *bp + (*mp)->m_len; 136283651Speter } 136383651Speter *tl = (u_int32_t *)*bp; 136483651Speter} 136583651Speter 136683651Speterint 136788091Siedowsenfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md, 136888091Siedowse caddr_t *dpos) 136983651Speter{ 137088091Siedowse u_int32_t *tl; 137183651Speter int fhlen; 137283651Speter 137383651Speter if (nfsd->nd_flag & ND_NFSV3) { 1374140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 137588091Siedowse if (tl == NULL) 137684057Speter return EBADRPC; 137788091Siedowse fhlen = fxdr_unsigned(int, *tl); 137883651Speter if (fhlen != 0 && fhlen != NFSX_V3FH) 137983651Speter return EBADRPC; 138083651Speter } else { 138183651Speter fhlen = NFSX_V2FH; 138283651Speter } 138383651Speter if (fhlen != 0) { 1384140495Sps tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos); 138588091Siedowse if (tl == NULL) 138684057Speter return EBADRPC; 138788091Siedowse bcopy((caddr_t)tl, (caddr_t)(f), fhlen); 138883651Speter } else { 138983651Speter bzero((caddr_t)(f), NFSX_V3FH); 139083651Speter } 139183651Speter return 0; 139283651Speter} 139383651Speter 139483651Speterint 139588091Siedowsenfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos) 139683651Speter{ 139788091Siedowse u_int32_t *tl; 1398157391Scel int toclient = 0; 139983651Speter 1400140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 140188091Siedowse if (tl == NULL) 140284057Speter return EBADRPC; 140389094Smsmith if (*tl == nfsrv_nfs_true) { 1404140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 140588091Siedowse if (tl == NULL) 140684057Speter return EBADRPC; 140788091Siedowse (a)->va_mode = nfstov_mode(*tl); 140883651Speter } 1409140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 141088091Siedowse if (tl == NULL) 141184057Speter return EBADRPC; 141289094Smsmith if (*tl == nfsrv_nfs_true) { 1413140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 141488091Siedowse if (tl == NULL) 141584057Speter return EBADRPC; 141688091Siedowse (a)->va_uid = fxdr_unsigned(uid_t, *tl); 141783651Speter } 1418140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 141988091Siedowse if (tl == NULL) 142084057Speter return EBADRPC; 142189094Smsmith if (*tl == nfsrv_nfs_true) { 1422140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 142388091Siedowse if (tl == NULL) 142484057Speter return EBADRPC; 142588091Siedowse (a)->va_gid = fxdr_unsigned(gid_t, *tl); 142683651Speter } 1427140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 142888091Siedowse if (tl == NULL) 142984057Speter return EBADRPC; 143089094Smsmith if (*tl == nfsrv_nfs_true) { 1431140495Sps tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 143288091Siedowse if (tl == NULL) 143384057Speter return EBADRPC; 143488091Siedowse (a)->va_size = fxdr_hyper(tl); 143583651Speter } 1436140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 143788091Siedowse if (tl == NULL) 143884057Speter return EBADRPC; 143988091Siedowse switch (fxdr_unsigned(int, *tl)) { 144083651Speter case NFSV3SATTRTIME_TOCLIENT: 1441140495Sps tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 144288091Siedowse if (tl == NULL) 144384057Speter return EBADRPC; 144488091Siedowse fxdr_nfsv3time(tl, &(a)->va_atime); 1445157391Scel toclient = 1; 144683651Speter break; 144783651Speter case NFSV3SATTRTIME_TOSERVER: 144883651Speter getnanotime(&(a)->va_atime); 1449157391Scel a->va_vaflags |= VA_UTIMES_NULL; 145083651Speter break; 145183651Speter } 1452140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 145388091Siedowse if (tl == NULL) 145484057Speter return EBADRPC; 145588091Siedowse switch (fxdr_unsigned(int, *tl)) { 145683651Speter case NFSV3SATTRTIME_TOCLIENT: 1457140495Sps tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 145888091Siedowse if (tl == NULL) 145984057Speter return EBADRPC; 146088091Siedowse fxdr_nfsv3time(tl, &(a)->va_mtime); 1461157391Scel a->va_vaflags &= ~VA_UTIMES_NULL; 146283651Speter break; 146383651Speter case NFSV3SATTRTIME_TOSERVER: 146483651Speter getnanotime(&(a)->va_mtime); 1465157391Scel if (toclient == 0) 1466157391Scel a->va_vaflags |= VA_UTIMES_NULL; 146783651Speter break; 146883651Speter } 146983651Speter return 0; 147083651Speter} 1471