nfs_srvsubs.c revision 159268
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 159268 2006-06-05 14:48:02Z kib $"); 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 10138894Sbdestatic int nfs_prev_nfssvc_sy_narg; 10238894Sbdestatic sy_call_t *nfs_prev_nfssvc_sy_call; 10338894Sbde 104129639Srwatsonstruct mtx nfsd_mtx; 105129639Srwatson 1069336Sdfr/* 1079336Sdfr * Mapping of old NFS Version 2 RPC numbers to generic numbers. 1089336Sdfr */ 109129639Srwatsonconst int nfsrv_nfsv3_procid[NFS_NPROCS] = { 1109336Sdfr NFSPROC_NULL, 1119336Sdfr NFSPROC_GETATTR, 1129336Sdfr NFSPROC_SETATTR, 1139336Sdfr NFSPROC_NOOP, 1149336Sdfr NFSPROC_LOOKUP, 1159336Sdfr NFSPROC_READLINK, 1169336Sdfr NFSPROC_READ, 1179336Sdfr NFSPROC_NOOP, 1189336Sdfr NFSPROC_WRITE, 1199336Sdfr NFSPROC_CREATE, 1209336Sdfr NFSPROC_REMOVE, 1219336Sdfr NFSPROC_RENAME, 1229336Sdfr NFSPROC_LINK, 1239336Sdfr NFSPROC_SYMLINK, 1249336Sdfr NFSPROC_MKDIR, 1259336Sdfr NFSPROC_RMDIR, 1269336Sdfr NFSPROC_READDIR, 1279336Sdfr NFSPROC_FSSTAT, 1289336Sdfr NFSPROC_NOOP, 1299336Sdfr NFSPROC_NOOP, 1309336Sdfr NFSPROC_NOOP, 1319336Sdfr NFSPROC_NOOP, 1329336Sdfr NFSPROC_NOOP, 1339336Sdfr}; 1349336Sdfr 1359336Sdfr/* 1369336Sdfr * and the reverse mapping from generic to Version 2 procedure numbers 1379336Sdfr */ 138129639Srwatsonconst int nfsrvv2_procid[NFS_NPROCS] = { 1399336Sdfr NFSV2PROC_NULL, 1409336Sdfr NFSV2PROC_GETATTR, 1419336Sdfr NFSV2PROC_SETATTR, 1429336Sdfr NFSV2PROC_LOOKUP, 1439336Sdfr NFSV2PROC_NOOP, 1449336Sdfr NFSV2PROC_READLINK, 1459336Sdfr NFSV2PROC_READ, 1469336Sdfr NFSV2PROC_WRITE, 1479336Sdfr NFSV2PROC_CREATE, 1489336Sdfr NFSV2PROC_MKDIR, 1499336Sdfr NFSV2PROC_SYMLINK, 1509336Sdfr NFSV2PROC_CREATE, 1519336Sdfr NFSV2PROC_REMOVE, 1529336Sdfr NFSV2PROC_RMDIR, 1539336Sdfr NFSV2PROC_RENAME, 1549336Sdfr NFSV2PROC_LINK, 1559336Sdfr NFSV2PROC_READDIR, 1569336Sdfr NFSV2PROC_NOOP, 1579336Sdfr NFSV2PROC_STATFS, 1589336Sdfr NFSV2PROC_NOOP, 1599336Sdfr NFSV2PROC_NOOP, 1609336Sdfr NFSV2PROC_NOOP, 1619336Sdfr NFSV2PROC_NOOP, 1629336Sdfr}; 1639336Sdfr 1649336Sdfr/* 1659336Sdfr * Maps errno values to nfs error numbers. 166102236Sphk * Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not 167102236Sphk * specifically defined in RFC 1094. 1689336Sdfr */ 169129639Srwatsonstatic const u_char nfsrv_v2errmap[ELAST] = { 170102236Sphk NFSERR_PERM, NFSERR_NOENT, 0, 0, 0, 171102236Sphk NFSERR_NXIO, 0, 0, 0, 0, 172102236Sphk 0, 0, NFSERR_ACCES, 0, 0, 173102236Sphk 0, NFSERR_EXIST, 0, NFSERR_NODEV, NFSERR_NOTDIR, 174102236Sphk NFSERR_ISDIR, 0, 0, 0, 0, 175102236Sphk 0, NFSERR_FBIG, NFSERR_NOSPC, 0, NFSERR_ROFS, 176102236Sphk 0, 0, 0, 0, 0, 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, NFSERR_NAMETOL, 0, 0, 183102236Sphk NFSERR_NOTEMPTY, 0, 0, NFSERR_DQUOT, NFSERR_STALE, 184102236Sphk 0 1859336Sdfr}; 1869336Sdfr 1879336Sdfr/* 1889336Sdfr * Maps errno values to nfs error numbers. 1899336Sdfr * Although it is not obvious whether or not NFS clients really care if 1909336Sdfr * a returned error value is in the specified list for the procedure, the 1919336Sdfr * safest thing to do is filter them appropriately. For Version 2, the 1929336Sdfr * X/Open XNFS document is the only specification that defines error values 1939336Sdfr * for each RPC (The RFC simply lists all possible error values for all RPCs), 1949336Sdfr * so I have decided to not do this for Version 2. 1959336Sdfr * The first entry is the default error return and the rest are the valid 1969336Sdfr * errors for that RPC in increasing numeric order. 1979336Sdfr */ 198129639Srwatsonstatic const short nfsv3err_null[] = { 1999336Sdfr 0, 2009336Sdfr 0, 2019336Sdfr}; 2029336Sdfr 203129639Srwatsonstatic const short nfsv3err_getattr[] = { 2049336Sdfr NFSERR_IO, 2059336Sdfr NFSERR_IO, 2069336Sdfr NFSERR_STALE, 2079336Sdfr NFSERR_BADHANDLE, 2089336Sdfr NFSERR_SERVERFAULT, 2099336Sdfr 0, 2109336Sdfr}; 2119336Sdfr 212129639Srwatsonstatic const short nfsv3err_setattr[] = { 2139336Sdfr NFSERR_IO, 2149336Sdfr NFSERR_PERM, 2159336Sdfr NFSERR_IO, 2169336Sdfr NFSERR_ACCES, 2179336Sdfr NFSERR_INVAL, 2189336Sdfr NFSERR_NOSPC, 2199336Sdfr NFSERR_ROFS, 2209336Sdfr NFSERR_DQUOT, 2219336Sdfr NFSERR_STALE, 2229336Sdfr NFSERR_BADHANDLE, 2239336Sdfr NFSERR_NOT_SYNC, 2249336Sdfr NFSERR_SERVERFAULT, 2259336Sdfr 0, 2269336Sdfr}; 2279336Sdfr 228129639Srwatsonstatic const short nfsv3err_lookup[] = { 2299336Sdfr NFSERR_IO, 2309336Sdfr NFSERR_NOENT, 2319336Sdfr NFSERR_IO, 2329336Sdfr NFSERR_ACCES, 2339336Sdfr NFSERR_NOTDIR, 2349336Sdfr NFSERR_NAMETOL, 2359336Sdfr NFSERR_STALE, 2369336Sdfr NFSERR_BADHANDLE, 2379336Sdfr NFSERR_SERVERFAULT, 2389336Sdfr 0, 2399336Sdfr}; 2409336Sdfr 241129639Srwatsonstatic const short nfsv3err_access[] = { 2429336Sdfr NFSERR_IO, 2439336Sdfr NFSERR_IO, 2449336Sdfr NFSERR_STALE, 2459336Sdfr NFSERR_BADHANDLE, 2469336Sdfr NFSERR_SERVERFAULT, 2479336Sdfr 0, 2489336Sdfr}; 2499336Sdfr 250129639Srwatsonstatic const short nfsv3err_readlink[] = { 2519336Sdfr NFSERR_IO, 2529336Sdfr NFSERR_IO, 2539336Sdfr NFSERR_ACCES, 2549336Sdfr NFSERR_INVAL, 2559336Sdfr NFSERR_STALE, 2569336Sdfr NFSERR_BADHANDLE, 2579336Sdfr NFSERR_NOTSUPP, 2589336Sdfr NFSERR_SERVERFAULT, 2599336Sdfr 0, 2609336Sdfr}; 2619336Sdfr 262129639Srwatsonstatic const short nfsv3err_read[] = { 2639336Sdfr NFSERR_IO, 2649336Sdfr NFSERR_IO, 2659336Sdfr NFSERR_NXIO, 2669336Sdfr NFSERR_ACCES, 2679336Sdfr NFSERR_INVAL, 2689336Sdfr NFSERR_STALE, 2699336Sdfr NFSERR_BADHANDLE, 2709336Sdfr NFSERR_SERVERFAULT, 2719336Sdfr 0, 2729336Sdfr}; 2739336Sdfr 274129639Srwatsonstatic const short nfsv3err_write[] = { 2759336Sdfr NFSERR_IO, 2769336Sdfr NFSERR_IO, 2779336Sdfr NFSERR_ACCES, 2789336Sdfr NFSERR_INVAL, 2799336Sdfr NFSERR_FBIG, 2809336Sdfr NFSERR_NOSPC, 2819336Sdfr NFSERR_ROFS, 2829336Sdfr NFSERR_DQUOT, 2839336Sdfr NFSERR_STALE, 2849336Sdfr NFSERR_BADHANDLE, 2859336Sdfr NFSERR_SERVERFAULT, 2869336Sdfr 0, 2879336Sdfr}; 2889336Sdfr 289129639Srwatsonstatic const short nfsv3err_create[] = { 2909336Sdfr NFSERR_IO, 2919336Sdfr NFSERR_IO, 2929336Sdfr NFSERR_ACCES, 2939336Sdfr NFSERR_EXIST, 2949336Sdfr NFSERR_NOTDIR, 2959336Sdfr NFSERR_NOSPC, 2969336Sdfr NFSERR_ROFS, 2979336Sdfr NFSERR_NAMETOL, 2989336Sdfr NFSERR_DQUOT, 2999336Sdfr NFSERR_STALE, 3009336Sdfr NFSERR_BADHANDLE, 3019336Sdfr NFSERR_NOTSUPP, 3029336Sdfr NFSERR_SERVERFAULT, 3039336Sdfr 0, 3049336Sdfr}; 3059336Sdfr 306129639Srwatsonstatic const short nfsv3err_mkdir[] = { 3079336Sdfr NFSERR_IO, 3089336Sdfr NFSERR_IO, 3099336Sdfr NFSERR_ACCES, 3109336Sdfr NFSERR_EXIST, 3119336Sdfr NFSERR_NOTDIR, 3129336Sdfr NFSERR_NOSPC, 3139336Sdfr NFSERR_ROFS, 3149336Sdfr NFSERR_NAMETOL, 3159336Sdfr NFSERR_DQUOT, 3169336Sdfr NFSERR_STALE, 3179336Sdfr NFSERR_BADHANDLE, 3189336Sdfr NFSERR_NOTSUPP, 3199336Sdfr NFSERR_SERVERFAULT, 3209336Sdfr 0, 3219336Sdfr}; 3229336Sdfr 323129639Srwatsonstatic const short nfsv3err_symlink[] = { 3249336Sdfr NFSERR_IO, 3259336Sdfr NFSERR_IO, 3269336Sdfr NFSERR_ACCES, 3279336Sdfr NFSERR_EXIST, 3289336Sdfr NFSERR_NOTDIR, 3299336Sdfr NFSERR_NOSPC, 3309336Sdfr NFSERR_ROFS, 3319336Sdfr NFSERR_NAMETOL, 3329336Sdfr NFSERR_DQUOT, 3339336Sdfr NFSERR_STALE, 3349336Sdfr NFSERR_BADHANDLE, 3359336Sdfr NFSERR_NOTSUPP, 3369336Sdfr NFSERR_SERVERFAULT, 3379336Sdfr 0, 3389336Sdfr}; 3399336Sdfr 340129639Srwatsonstatic const short nfsv3err_mknod[] = { 3419336Sdfr NFSERR_IO, 3429336Sdfr NFSERR_IO, 3439336Sdfr NFSERR_ACCES, 3449336Sdfr NFSERR_EXIST, 3459336Sdfr NFSERR_NOTDIR, 3469336Sdfr NFSERR_NOSPC, 3479336Sdfr NFSERR_ROFS, 3489336Sdfr NFSERR_NAMETOL, 3499336Sdfr NFSERR_DQUOT, 3509336Sdfr NFSERR_STALE, 3519336Sdfr NFSERR_BADHANDLE, 3529336Sdfr NFSERR_NOTSUPP, 3539336Sdfr NFSERR_SERVERFAULT, 3549336Sdfr NFSERR_BADTYPE, 3559336Sdfr 0, 3569336Sdfr}; 3579336Sdfr 358129639Srwatsonstatic const short nfsv3err_remove[] = { 3599336Sdfr NFSERR_IO, 3609336Sdfr NFSERR_NOENT, 3619336Sdfr NFSERR_IO, 3629336Sdfr NFSERR_ACCES, 3639336Sdfr NFSERR_NOTDIR, 3649336Sdfr NFSERR_ROFS, 3659336Sdfr NFSERR_NAMETOL, 3669336Sdfr NFSERR_STALE, 3679336Sdfr NFSERR_BADHANDLE, 3689336Sdfr NFSERR_SERVERFAULT, 3699336Sdfr 0, 3709336Sdfr}; 3719336Sdfr 372129639Srwatsonstatic const short nfsv3err_rmdir[] = { 3739336Sdfr NFSERR_IO, 3749336Sdfr NFSERR_NOENT, 3759336Sdfr NFSERR_IO, 3769336Sdfr NFSERR_ACCES, 3779336Sdfr NFSERR_EXIST, 3789336Sdfr NFSERR_NOTDIR, 3799336Sdfr NFSERR_INVAL, 3809336Sdfr NFSERR_ROFS, 3819336Sdfr NFSERR_NAMETOL, 3829336Sdfr NFSERR_NOTEMPTY, 3839336Sdfr NFSERR_STALE, 3849336Sdfr NFSERR_BADHANDLE, 3859336Sdfr NFSERR_NOTSUPP, 3869336Sdfr NFSERR_SERVERFAULT, 3879336Sdfr 0, 3889336Sdfr}; 3899336Sdfr 390129639Srwatsonstatic const short nfsv3err_rename[] = { 3919336Sdfr NFSERR_IO, 3929336Sdfr NFSERR_NOENT, 3939336Sdfr NFSERR_IO, 3949336Sdfr NFSERR_ACCES, 3959336Sdfr NFSERR_EXIST, 3969336Sdfr NFSERR_XDEV, 3979336Sdfr NFSERR_NOTDIR, 3989336Sdfr NFSERR_ISDIR, 3999336Sdfr NFSERR_INVAL, 4009336Sdfr NFSERR_NOSPC, 4019336Sdfr NFSERR_ROFS, 4029336Sdfr NFSERR_MLINK, 4039336Sdfr NFSERR_NAMETOL, 4049336Sdfr NFSERR_NOTEMPTY, 4059336Sdfr NFSERR_DQUOT, 4069336Sdfr NFSERR_STALE, 4079336Sdfr NFSERR_BADHANDLE, 4089336Sdfr NFSERR_NOTSUPP, 4099336Sdfr NFSERR_SERVERFAULT, 4109336Sdfr 0, 4119336Sdfr}; 4129336Sdfr 413129639Srwatsonstatic const short nfsv3err_link[] = { 4149336Sdfr NFSERR_IO, 4159336Sdfr NFSERR_IO, 4169336Sdfr NFSERR_ACCES, 4179336Sdfr NFSERR_EXIST, 4189336Sdfr NFSERR_XDEV, 4199336Sdfr NFSERR_NOTDIR, 4209336Sdfr NFSERR_INVAL, 4219336Sdfr NFSERR_NOSPC, 4229336Sdfr NFSERR_ROFS, 4239336Sdfr NFSERR_MLINK, 4249336Sdfr NFSERR_NAMETOL, 4259336Sdfr NFSERR_DQUOT, 4269336Sdfr NFSERR_STALE, 4279336Sdfr NFSERR_BADHANDLE, 4289336Sdfr NFSERR_NOTSUPP, 4299336Sdfr NFSERR_SERVERFAULT, 4309336Sdfr 0, 4319336Sdfr}; 4329336Sdfr 433129639Srwatsonstatic const short nfsv3err_readdir[] = { 4349336Sdfr NFSERR_IO, 4359336Sdfr NFSERR_IO, 4369336Sdfr NFSERR_ACCES, 4379336Sdfr NFSERR_NOTDIR, 4389336Sdfr NFSERR_STALE, 4399336Sdfr NFSERR_BADHANDLE, 4409336Sdfr NFSERR_BAD_COOKIE, 4419336Sdfr NFSERR_TOOSMALL, 4429336Sdfr NFSERR_SERVERFAULT, 4439336Sdfr 0, 4449336Sdfr}; 4459336Sdfr 446129639Srwatsonstatic const short nfsv3err_readdirplus[] = { 4479336Sdfr NFSERR_IO, 4489336Sdfr NFSERR_IO, 4499336Sdfr NFSERR_ACCES, 4509336Sdfr NFSERR_NOTDIR, 4519336Sdfr NFSERR_STALE, 4529336Sdfr NFSERR_BADHANDLE, 4539336Sdfr NFSERR_BAD_COOKIE, 4549336Sdfr NFSERR_NOTSUPP, 4559336Sdfr NFSERR_TOOSMALL, 4569336Sdfr NFSERR_SERVERFAULT, 4579336Sdfr 0, 4589336Sdfr}; 4599336Sdfr 460129639Srwatsonstatic const short nfsv3err_fsstat[] = { 4619336Sdfr NFSERR_IO, 4629336Sdfr NFSERR_IO, 4639336Sdfr NFSERR_STALE, 4649336Sdfr NFSERR_BADHANDLE, 4659336Sdfr NFSERR_SERVERFAULT, 4669336Sdfr 0, 4679336Sdfr}; 4689336Sdfr 469129639Srwatsonstatic const short nfsv3err_fsinfo[] = { 4709336Sdfr NFSERR_STALE, 4719336Sdfr NFSERR_STALE, 4729336Sdfr NFSERR_BADHANDLE, 4739336Sdfr NFSERR_SERVERFAULT, 4749336Sdfr 0, 4759336Sdfr}; 4769336Sdfr 477129639Srwatsonstatic const short nfsv3err_pathconf[] = { 4789336Sdfr NFSERR_STALE, 4799336Sdfr NFSERR_STALE, 4809336Sdfr NFSERR_BADHANDLE, 4819336Sdfr NFSERR_SERVERFAULT, 4829336Sdfr 0, 4839336Sdfr}; 4849336Sdfr 485129639Srwatsonstatic const short nfsv3err_commit[] = { 4869336Sdfr NFSERR_IO, 4879336Sdfr NFSERR_IO, 4889336Sdfr NFSERR_STALE, 4899336Sdfr NFSERR_BADHANDLE, 4909336Sdfr NFSERR_SERVERFAULT, 4919336Sdfr 0, 4929336Sdfr}; 4939336Sdfr 494129639Srwatsonstatic const short *nfsrv_v3errmap[] = { 4959336Sdfr nfsv3err_null, 4969336Sdfr nfsv3err_getattr, 4979336Sdfr nfsv3err_setattr, 4989336Sdfr nfsv3err_lookup, 4999336Sdfr nfsv3err_access, 5009336Sdfr nfsv3err_readlink, 5019336Sdfr nfsv3err_read, 5029336Sdfr nfsv3err_write, 5039336Sdfr nfsv3err_create, 5049336Sdfr nfsv3err_mkdir, 5059336Sdfr nfsv3err_symlink, 5069336Sdfr nfsv3err_mknod, 5079336Sdfr nfsv3err_remove, 5089336Sdfr nfsv3err_rmdir, 5099336Sdfr nfsv3err_rename, 5109336Sdfr nfsv3err_link, 5119336Sdfr nfsv3err_readdir, 5129336Sdfr nfsv3err_readdirplus, 5139336Sdfr nfsv3err_fsstat, 5149336Sdfr nfsv3err_fsinfo, 5159336Sdfr nfsv3err_pathconf, 5169336Sdfr nfsv3err_commit, 5179336Sdfr}; 5189336Sdfr 5191541Srgrimes/* 5201541Srgrimes * Called once to initialize data structures... 5211541Srgrimes */ 52283651Speterstatic int 52383700Speternfsrv_modevent(module_t mod, int type, void *data) 5241541Srgrimes{ 525132199Sphk int error = 0; 5261541Srgrimes 527129639Srwatson NET_LOCK_GIANT(); 52883700Speter switch (type) { 52983700Speter case MOD_LOAD: 530129639Srwatson mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF); 53189094Smsmith nfsrv_rpc_vers = txdr_unsigned(RPC_VER2); 53289094Smsmith nfsrv_rpc_call = txdr_unsigned(RPC_CALL); 53389094Smsmith nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY); 53489094Smsmith nfsrv_rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 53589094Smsmith nfsrv_rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 53689094Smsmith nfsrv_rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 53789094Smsmith nfsrv_rpc_autherr = txdr_unsigned(RPC_AUTHERR); 53889094Smsmith nfsrv_rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 53989094Smsmith nfsrv_nfs_prog = txdr_unsigned(NFS_PROG); 54089094Smsmith nfsrv_nfs_true = txdr_unsigned(TRUE); 54189094Smsmith nfsrv_nfs_false = txdr_unsigned(FALSE); 54289094Smsmith nfsrv_nfs_xdrneg1 = txdr_unsigned(-1); 54389094Smsmith nfsrv_ticks = (hz * NFS_TICKINTVL + 500) / 1000; 54489094Smsmith if (nfsrv_ticks < 1) 54589094Smsmith nfsrv_ticks = 1; 54683651Speter 547129639Srwatson nfsrv_initcache(); /* Init the server request cache */ 548129639Srwatson NFSD_LOCK(); 54983700Speter nfsrv_init(0); /* Init server data structures */ 550132591Srwatson if (debug_mpsafenet) 551132591Srwatson callout_init(&nfsrv_callout, CALLOUT_MPSAFE); 552132591Srwatson else 553132591Srwatson callout_init(&nfsrv_callout, 0); 554129639Srwatson NFSD_UNLOCK(); 55583700Speter nfsrv_timer(0); 5561541Srgrimes 55783700Speter nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg; 558129888Srwatson sysent[SYS_nfssvc].sy_narg = 2 | SYF_MPSAFE; 55983700Speter nfs_prev_nfssvc_sy_call = sysent[SYS_nfssvc].sy_call; 56083700Speter sysent[SYS_nfssvc].sy_call = (sy_call_t *)nfssvc; 56183700Speter break; 5622997Swollman 563132199Sphk case MOD_UNLOAD: 564129902Sbmilekic if (nfsrv_numnfsd != 0) { 565132199Sphk error = EBUSY; 566132199Sphk break; 567129902Sbmilekic } 56883700Speter 569126723Skan callout_stop(&nfsrv_callout); 57083700Speter sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg; 57183700Speter sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call; 572129639Srwatson mtx_destroy(&nfsd_mtx); 57383700Speter break; 574132199Sphk default: 575132199Sphk error = EOPNOTSUPP; 576132199Sphk break; 57783700Speter } 578129639Srwatson NET_UNLOCK_GIANT(); 579132199Sphk return error; 5801541Srgrimes} 58183700Speterstatic moduledata_t nfsserver_mod = { 58283700Speter "nfsserver", 58383700Speter nfsrv_modevent, 58483700Speter NULL, 58583700Speter}; 58683700SpeterDECLARE_MODULE(nfsserver, nfsserver_mod, SI_SUB_VFS, SI_ORDER_ANY); 5871541Srgrimes 58883700Speter/* So that loader and kldload(2) can find us, wherever we are.. */ 58983700SpeterMODULE_VERSION(nfsserver, 1); 59038894Sbde 5911541Srgrimes/* 59227446Sdfr * Set up nameidata for a lookup() call and do it. 59327446Sdfr * 59427446Sdfr * If pubflag is set, this call is done for a lookup operation on the 59527446Sdfr * public filehandle. In that case we allow crossing mountpoints and 59627446Sdfr * absolute pathnames. However, the caller is expected to check that 59727446Sdfr * the lookup result is within the public fs, and deny access if 59827446Sdfr * it is not. 59948125Sjulian * 60048125Sjulian * nfs_namei() clears out garbage fields that namei() might leave garbage. 60148125Sjulian * This is mainly ni_vp and ni_dvp when an error occurs, and ni_dvp when no 60248125Sjulian * error occurs but the parent was not requested. 60348125Sjulian * 60483651Speter * dirp may be set whether an error is returned or not, and must be 60548125Sjulian * released by the caller. 6061541Srgrimes */ 6071549Srgrimesint 60883651Speternfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, 60983651Speter struct nfssvc_sock *slp, struct sockaddr *nam, struct mbuf **mdp, 610115301Struckman caddr_t *dposp, struct vnode **retdirp, int v3, struct vattr *retdirattrp, 611115301Struckman int *retdirattr_retp, struct thread *td, int pubflag) 6121541Srgrimes{ 61383651Speter int i, rem; 61483651Speter struct mbuf *md; 61583651Speter char *fromcp, *tocp, *cp; 61627446Sdfr struct iovec aiov; 61727446Sdfr struct uio auio; 6181541Srgrimes struct vnode *dp; 61927446Sdfr int error, rdonly, linklen; 6201541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 621115301Struckman int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0; 6221541Srgrimes 623129639Srwatson NFSD_LOCK_ASSERT(); 624129639Srwatson NFSD_UNLOCK(); 625129639Srwatson mtx_lock(&Giant); /* VFS */ 626129639Srwatson 62799797Sdillon *retdirp = NULL; 628105481Srwatson cnp->cn_flags |= NOMACCHECK; 629111119Simp cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK); 63029653Sdyson 6311541Srgrimes /* 6321541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 6331541Srgrimes * and set the various ndp fields appropriately. 6341541Srgrimes */ 6351541Srgrimes fromcp = *dposp; 6361541Srgrimes tocp = cnp->cn_pnbuf; 6371541Srgrimes md = *mdp; 6381541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 6391541Srgrimes for (i = 0; i < len; i++) { 6401541Srgrimes while (rem == 0) { 6411541Srgrimes md = md->m_next; 6421541Srgrimes if (md == NULL) { 6431541Srgrimes error = EBADRPC; 6441541Srgrimes goto out; 6451541Srgrimes } 6461541Srgrimes fromcp = mtod(md, caddr_t); 6471541Srgrimes rem = md->m_len; 6481541Srgrimes } 64927446Sdfr if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { 6509336Sdfr error = EACCES; 6511541Srgrimes goto out; 6521541Srgrimes } 6531541Srgrimes *tocp++ = *fromcp++; 6541541Srgrimes rem--; 6551541Srgrimes } 6561541Srgrimes *tocp = '\0'; 6571541Srgrimes *mdp = md; 6581541Srgrimes *dposp = fromcp; 6591541Srgrimes len = nfsm_rndup(len)-len; 6601541Srgrimes if (len > 0) { 6611541Srgrimes if (rem >= len) 6621541Srgrimes *dposp += len; 66327609Sdfr else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 6649336Sdfr goto out; 6651541Srgrimes } 66627446Sdfr 6671541Srgrimes /* 6681541Srgrimes * Extract and set starting directory. 6691541Srgrimes */ 670129639Srwatson mtx_unlock(&Giant); /* VFS */ 671129639Srwatson NFSD_LOCK(); 67227446Sdfr error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 67383651Speter nam, &rdonly, pubflag); 674129639Srwatson NFSD_UNLOCK(); 675129639Srwatson mtx_lock(&Giant); /* VFS */ 67627446Sdfr if (error) 6771541Srgrimes goto out; 6781541Srgrimes if (dp->v_type != VDIR) { 67917761Sdyson vrele(dp); 6801541Srgrimes error = ENOTDIR; 6811541Srgrimes goto out; 6821541Srgrimes } 68327446Sdfr 68427446Sdfr if (rdonly) 68527446Sdfr cnp->cn_flags |= RDONLY; 68627446Sdfr 68748125Sjulian /* 68883651Speter * Set return directory. Reference to dp is implicitly transfered 68948125Sjulian * to the returned pointer 69048125Sjulian */ 69127609Sdfr *retdirp = dp; 692115301Struckman if (v3) { 693115301Struckman vn_lock(dp, LK_EXCLUSIVE | LK_RETRY, td); 694115301Struckman *retdirattr_retp = VOP_GETATTR(dp, retdirattrp, 695115301Struckman ndp->ni_cnd.cn_cred, td); 696115301Struckman VOP_UNLOCK(dp, 0, td); 697115301Struckman } 69827609Sdfr 69927446Sdfr if (pubflag) { 70027446Sdfr /* 70127446Sdfr * Oh joy. For WebNFS, handle those pesky '%' escapes, 70227446Sdfr * and the 'native path' indicator. 70327446Sdfr */ 704111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 70527446Sdfr fromcp = cnp->cn_pnbuf; 70627446Sdfr tocp = cp; 70727446Sdfr if ((unsigned char)*fromcp >= WEBNFS_SPECCHAR_START) { 70827446Sdfr switch ((unsigned char)*fromcp) { 70927446Sdfr case WEBNFS_NATIVE_CHAR: 71027446Sdfr /* 71127446Sdfr * 'Native' path for us is the same 71227446Sdfr * as a path according to the NFS spec, 71327446Sdfr * just skip the escape char. 71427446Sdfr */ 71527446Sdfr fromcp++; 71627446Sdfr break; 71727446Sdfr /* 71827446Sdfr * More may be added in the future, range 0x80-0xff 71927446Sdfr */ 72027446Sdfr default: 72127446Sdfr error = EIO; 72292783Sjeff uma_zfree(namei_zone, cp); 72327446Sdfr goto out; 72427446Sdfr } 72527446Sdfr } 72627446Sdfr /* 72727446Sdfr * Translate the '%' escapes, URL-style. 72827446Sdfr */ 72927446Sdfr while (*fromcp != '\0') { 73027446Sdfr if (*fromcp == WEBNFS_ESC_CHAR) { 73127446Sdfr if (fromcp[1] != '\0' && fromcp[2] != '\0') { 73227446Sdfr fromcp++; 73327446Sdfr *tocp++ = HEXSTRTOI(fromcp); 73427446Sdfr fromcp += 2; 73527446Sdfr continue; 73627446Sdfr } else { 73727446Sdfr error = ENOENT; 73892783Sjeff uma_zfree(namei_zone, cp); 73927446Sdfr goto out; 74027446Sdfr } 74127446Sdfr } else 74227446Sdfr *tocp++ = *fromcp++; 74327446Sdfr } 74427446Sdfr *tocp = '\0'; 74592783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 74627446Sdfr cnp->cn_pnbuf = cp; 74727446Sdfr } 74827446Sdfr 74927446Sdfr ndp->ni_pathlen = (tocp - cnp->cn_pnbuf) + 1; 75027446Sdfr ndp->ni_segflg = UIO_SYSSPACE; 75127446Sdfr 75227446Sdfr if (pubflag) { 75327446Sdfr ndp->ni_rootdir = rootvnode; 75427446Sdfr ndp->ni_loopcnt = 0; 75527446Sdfr if (cnp->cn_pnbuf[0] == '/') 75627446Sdfr dp = rootvnode; 75727446Sdfr } else { 75827609Sdfr cnp->cn_flags |= NOCROSSMOUNT; 75927446Sdfr } 76027446Sdfr 76148125Sjulian /* 76248125Sjulian * Initialize for scan, set ni_startdir and bump ref on dp again 763123608Sjhb * because lookup() will dereference ni_startdir. 76448125Sjulian */ 76548125Sjulian 76683366Sjulian cnp->cn_thread = td; 7679336Sdfr VREF(dp); 76848125Sjulian ndp->ni_startdir = dp; 76927446Sdfr 770115301Struckman if (!lockleaf) 771115301Struckman cnp->cn_flags |= LOCKLEAF; 77248125Sjulian for (;;) { 77348125Sjulian cnp->cn_nameptr = cnp->cn_pnbuf; 77448125Sjulian /* 77548125Sjulian * Call lookup() to do the real work. If an error occurs, 77648125Sjulian * ndp->ni_vp and ni_dvp are left uninitialized or NULL and 77748125Sjulian * we do not have to dereference anything before returning. 77848125Sjulian * In either case ni_startdir will be dereferenced and NULLed 77948125Sjulian * out. 78048125Sjulian */ 78148125Sjulian error = lookup(ndp); 78248125Sjulian if (error) 78348125Sjulian break; 78448125Sjulian 78548125Sjulian /* 78683651Speter * Check for encountering a symbolic link. Trivial 78748125Sjulian * termination occurs if no symlink encountered. 78848125Sjulian * Note: zfree is safe because error is 0, so we will 78948125Sjulian * not zfree it again when we break. 79048125Sjulian */ 79148125Sjulian if ((cnp->cn_flags & ISSYMLINK) == 0) { 79248125Sjulian if (cnp->cn_flags & (SAVENAME | SAVESTART)) 79348125Sjulian cnp->cn_flags |= HASBUF; 79448125Sjulian else 79592783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 796115301Struckman if (ndp->ni_vp && !lockleaf) 797115301Struckman VOP_UNLOCK(ndp->ni_vp, 0, td); 79848125Sjulian break; 79927446Sdfr } 80048125Sjulian 80148125Sjulian /* 80248125Sjulian * Validate symlink 80348125Sjulian */ 8041541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 80583366Sjulian VOP_UNLOCK(ndp->ni_dvp, 0, td); 80627446Sdfr if (!pubflag) { 80727446Sdfr error = EINVAL; 80848125Sjulian goto badlink2; 80927446Sdfr } 81027446Sdfr 81127446Sdfr if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 81227446Sdfr error = ELOOP; 81348125Sjulian goto badlink2; 81427446Sdfr } 81527609Sdfr if (ndp->ni_pathlen > 1) 816111119Simp cp = uma_zalloc(namei_zone, M_WAITOK); 8171541Srgrimes else 81827446Sdfr cp = cnp->cn_pnbuf; 81927446Sdfr aiov.iov_base = cp; 82027446Sdfr aiov.iov_len = MAXPATHLEN; 82127446Sdfr auio.uio_iov = &aiov; 82227446Sdfr auio.uio_iovcnt = 1; 82327446Sdfr auio.uio_offset = 0; 82427446Sdfr auio.uio_rw = UIO_READ; 82527446Sdfr auio.uio_segflg = UIO_SYSSPACE; 82699797Sdillon auio.uio_td = NULL; 82727446Sdfr auio.uio_resid = MAXPATHLEN; 82827446Sdfr error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred); 82927446Sdfr if (error) { 83048125Sjulian badlink1: 83127446Sdfr if (ndp->ni_pathlen > 1) 83292783Sjeff uma_zfree(namei_zone, cp); 83348125Sjulian badlink2: 834155160Sjeff vput(ndp->ni_vp); 83548125Sjulian vrele(ndp->ni_dvp); 83627446Sdfr break; 83727446Sdfr } 83827446Sdfr linklen = MAXPATHLEN - auio.uio_resid; 83927446Sdfr if (linklen == 0) { 84027446Sdfr error = ENOENT; 84148125Sjulian goto badlink1; 84227446Sdfr } 84327446Sdfr if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 84427446Sdfr error = ENAMETOOLONG; 84548125Sjulian goto badlink1; 84627446Sdfr } 84748125Sjulian 84848125Sjulian /* 84948125Sjulian * Adjust or replace path 85048125Sjulian */ 85127446Sdfr if (ndp->ni_pathlen > 1) { 85227446Sdfr bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 85392783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 85427446Sdfr cnp->cn_pnbuf = cp; 85527446Sdfr } else 85627446Sdfr cnp->cn_pnbuf[linklen] = '\0'; 85727446Sdfr ndp->ni_pathlen += linklen; 85848125Sjulian 85927446Sdfr /* 86083651Speter * Cleanup refs for next loop and check if root directory 86183651Speter * should replace current directory. Normally ni_dvp 86248125Sjulian * becomes the new base directory and is cleaned up when 86348125Sjulian * we loop. Explicitly null pointers after invalidation 86448125Sjulian * to clarify operation. 86527446Sdfr */ 86648125Sjulian vput(ndp->ni_vp); 86748125Sjulian ndp->ni_vp = NULL; 86848125Sjulian 86927446Sdfr if (cnp->cn_pnbuf[0] == '/') { 87048125Sjulian vrele(ndp->ni_dvp); 87148125Sjulian ndp->ni_dvp = ndp->ni_rootdir; 87248125Sjulian VREF(ndp->ni_dvp); 87327446Sdfr } 87448125Sjulian ndp->ni_startdir = ndp->ni_dvp; 87548125Sjulian ndp->ni_dvp = NULL; 8761541Srgrimes } 877115301Struckman if (!lockleaf) 878115301Struckman cnp->cn_flags &= ~LOCKLEAF; 879159268Skib if (cnp->cn_flags & GIANTHELD) { 880159268Skib mtx_unlock(&Giant); 881159268Skib cnp->cn_flags &= ~GIANTHELD; 882159268Skib } 88348125Sjulian 88448125Sjulian /* 88548125Sjulian * nfs_namei() guarentees that fields will not contain garbage 88648125Sjulian * whether an error occurs or not. This allows the caller to track 88748125Sjulian * cleanup state trivially. 88848125Sjulian */ 8891541Srgrimesout: 89048125Sjulian if (error) { 89192783Sjeff uma_zfree(namei_zone, cnp->cn_pnbuf); 89248125Sjulian ndp->ni_vp = NULL; 89348125Sjulian ndp->ni_dvp = NULL; 89448125Sjulian ndp->ni_startdir = NULL; 89548125Sjulian cnp->cn_flags &= ~HASBUF; 89648125Sjulian } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { 89748125Sjulian ndp->ni_dvp = NULL; 89848125Sjulian } 899129639Srwatson mtx_unlock(&Giant); /* VFS */ 900129639Srwatson NFSD_LOCK(); 9011541Srgrimes return (error); 9021541Srgrimes} 9031541Srgrimes 9041541Srgrimes/* 9051541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 9061541Srgrimes * boundary and only trims off the back end 9071541Srgrimes */ 9081541Srgrimesvoid 90983651Speternfsm_adj(struct mbuf *mp, int len, int nul) 9101541Srgrimes{ 91183651Speter struct mbuf *m; 91283651Speter int count, i; 91383651Speter char *cp; 9141541Srgrimes 915129639Srwatson NFSD_LOCK_DONTCARE(); 916129639Srwatson 9171541Srgrimes /* 9181541Srgrimes * Trim from tail. Scan the mbuf chain, 9191541Srgrimes * calculating its length and finding the last mbuf. 9201541Srgrimes * If the adjustment only affects this mbuf, then just 9211541Srgrimes * adjust and return. Otherwise, rescan and truncate 9221541Srgrimes * after the remaining size. 9231541Srgrimes */ 9241541Srgrimes count = 0; 9251541Srgrimes m = mp; 9261541Srgrimes for (;;) { 9271541Srgrimes count += m->m_len; 92899797Sdillon if (m->m_next == NULL) 9291541Srgrimes break; 9301541Srgrimes m = m->m_next; 9311541Srgrimes } 9321541Srgrimes if (m->m_len > len) { 9331541Srgrimes m->m_len -= len; 9341541Srgrimes if (nul > 0) { 9351541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 9361541Srgrimes for (i = 0; i < nul; i++) 9371541Srgrimes *cp++ = '\0'; 9381541Srgrimes } 9391541Srgrimes return; 9401541Srgrimes } 9411541Srgrimes count -= len; 9421541Srgrimes if (count < 0) 9431541Srgrimes count = 0; 9441541Srgrimes /* 9451541Srgrimes * Correct length for chain is "count". 9461541Srgrimes * Find the mbuf with last data, adjust its length, 9471541Srgrimes * and toss data from remaining mbufs on chain. 9481541Srgrimes */ 9491541Srgrimes for (m = mp; m; m = m->m_next) { 9501541Srgrimes if (m->m_len >= count) { 9511541Srgrimes m->m_len = count; 9521541Srgrimes if (nul > 0) { 9531541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 9541541Srgrimes for (i = 0; i < nul; i++) 9551541Srgrimes *cp++ = '\0'; 9561541Srgrimes } 957144246Ssam if (m->m_next != NULL) { 958144246Ssam m_freem(m->m_next); 959144246Ssam m->m_next = NULL; 960144246Ssam } 9611541Srgrimes break; 9621541Srgrimes } 9631541Srgrimes count -= m->m_len; 9641541Srgrimes } 9651541Srgrimes} 9661541Srgrimes 9671541Srgrimes/* 9689336Sdfr * Make these functions instead of macros, so that the kernel text size 9699336Sdfr * doesn't get too big... 9709336Sdfr */ 9719336Sdfrvoid 97283651Speternfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 97383651Speter struct vattr *before_vap, int after_ret, struct vattr *after_vap, 97483651Speter struct mbuf **mbp, char **bposp) 9759336Sdfr{ 97683651Speter struct mbuf *mb = *mbp; 97783651Speter char *bpos = *bposp; 97883651Speter u_int32_t *tl; 9799336Sdfr 9809336Sdfr if (before_ret) { 98184002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 98289094Smsmith *tl = nfsrv_nfs_false; 9839336Sdfr } else { 98484002Speter tl = nfsm_build(u_int32_t *, 7 * NFSX_UNSIGNED); 98589094Smsmith *tl++ = nfsrv_nfs_true; 98647751Speter txdr_hyper(before_vap->va_size, tl); 9879336Sdfr tl += 2; 9889336Sdfr txdr_nfsv3time(&(before_vap->va_mtime), tl); 9899336Sdfr tl += 2; 9909336Sdfr txdr_nfsv3time(&(before_vap->va_ctime), tl); 9919336Sdfr } 9929336Sdfr *bposp = bpos; 9939336Sdfr *mbp = mb; 9949336Sdfr nfsm_srvpostopattr(nfsd, after_ret, after_vap, mbp, bposp); 9959336Sdfr} 9969336Sdfr 9979336Sdfrvoid 99883651Speternfsm_srvpostopattr(struct nfsrv_descript *nfsd, int after_ret, 99983651Speter struct vattr *after_vap, struct mbuf **mbp, char **bposp) 10009336Sdfr{ 100183651Speter struct mbuf *mb = *mbp; 100283651Speter char *bpos = *bposp; 100383651Speter u_int32_t *tl; 100483651Speter struct nfs_fattr *fp; 10059336Sdfr 10069336Sdfr if (after_ret) { 100784002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED); 100889094Smsmith *tl = nfsrv_nfs_false; 10099336Sdfr } else { 101084002Speter tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED + NFSX_V3FATTR); 101189094Smsmith *tl++ = nfsrv_nfs_true; 10129336Sdfr fp = (struct nfs_fattr *)tl; 10139336Sdfr nfsm_srvfattr(nfsd, after_vap, fp); 10149336Sdfr } 10159336Sdfr *mbp = mb; 10169336Sdfr *bposp = bpos; 10179336Sdfr} 10189336Sdfr 10199336Sdfrvoid 102083651Speternfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 102183651Speter struct nfs_fattr *fp) 10229336Sdfr{ 10239336Sdfr 10249336Sdfr fp->fa_nlink = txdr_unsigned(vap->va_nlink); 10259336Sdfr fp->fa_uid = txdr_unsigned(vap->va_uid); 10269336Sdfr fp->fa_gid = txdr_unsigned(vap->va_gid); 10279336Sdfr if (nfsd->nd_flag & ND_NFSV3) { 10289336Sdfr fp->fa_type = vtonfsv3_type(vap->va_type); 10299336Sdfr fp->fa_mode = vtonfsv3_mode(vap->va_mode); 103047751Speter txdr_hyper(vap->va_size, &fp->fa3_size); 103147751Speter txdr_hyper(vap->va_bytes, &fp->fa3_used); 103247028Sphk fp->fa3_rdev.specdata1 = txdr_unsigned(umajor(vap->va_rdev)); 103347028Sphk fp->fa3_rdev.specdata2 = txdr_unsigned(uminor(vap->va_rdev)); 10349336Sdfr fp->fa3_fsid.nfsuquad[0] = 0; 10359336Sdfr fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 10369336Sdfr fp->fa3_fileid.nfsuquad[0] = 0; 10379336Sdfr fp->fa3_fileid.nfsuquad[1] = txdr_unsigned(vap->va_fileid); 10389336Sdfr txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 10399336Sdfr txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 10409336Sdfr txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 10419336Sdfr } else { 10429336Sdfr fp->fa_type = vtonfsv2_type(vap->va_type); 10439336Sdfr fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 10449336Sdfr fp->fa2_size = txdr_unsigned(vap->va_size); 10459336Sdfr fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 10469336Sdfr if (vap->va_type == VFIFO) 10479336Sdfr fp->fa2_rdev = 0xffffffff; 10489336Sdfr else 10499336Sdfr fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 10509336Sdfr fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 10519336Sdfr fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 10529336Sdfr fp->fa2_fileid = txdr_unsigned(vap->va_fileid); 10539336Sdfr txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 10549336Sdfr txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 10559336Sdfr txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 10569336Sdfr } 10579336Sdfr} 10589336Sdfr 10599336Sdfr/* 10601541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 10611541Srgrimes * - look up fsid in mount list (if not found ret error) 10621541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 10631541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 10641541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 10651541Srgrimes */ 10661549Srgrimesint 106783651Speternfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, 106883651Speter struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, 106983651Speter int *rdonlyp, int pubflag) 10701541Srgrimes{ 107183366Sjulian struct thread *td = curthread; /* XXX */ 107283651Speter struct mount *mp; 107383651Speter int i; 10741541Srgrimes struct ucred *credanon; 10751541Srgrimes int error, exflags; 1076157325Sjeff int vfslocked; 107736534Speter#ifdef MNT_EXNORESPORT /* XXX needs mountd and /etc/exports help yet */ 107836534Speter struct sockaddr_int *saddr; 107936534Speter#endif 10801541Srgrimes 1081129639Srwatson NFSD_LOCK_ASSERT(); 1082129639Srwatson 108399797Sdillon *vpp = NULL; 108427446Sdfr 108527446Sdfr if (nfs_ispublicfh(fhp)) { 108627446Sdfr if (!pubflag || !nfs_pub.np_valid) 108727446Sdfr return (ESTALE); 108827446Sdfr fhp = &nfs_pub.np_handle; 108927446Sdfr } 109027446Sdfr 109122521Sdyson mp = vfs_getvfs(&fhp->fh_fsid); 10923305Sphk if (!mp) 10931541Srgrimes return (ESTALE); 1094129639Srwatson NFSD_UNLOCK(); 1095157325Sjeff vfslocked = VFS_LOCK_GIANT(mp); 109651138Salfred error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 10973305Sphk if (error) 1098129639Srwatson goto out; 109951138Salfred error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 110051138Salfred if (error) 1101129639Srwatson goto out; 110236534Speter#ifdef MNT_EXNORESPORT 110336534Speter if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) { 110436534Speter saddr = (struct sockaddr_in *)nam; 1105100134Salfred if ((saddr->sin_family == AF_INET || 1106100134Salfred saddr->sin_family == AF_INET6) && 1107100134Salfred /* same code for INET and INET6: sin*_port at same offet */ 110836534Speter ntohs(saddr->sin_port) >= IPPORT_RESERVED) { 110936534Speter vput(*vpp); 111054485Sdillon *vpp = NULL; 1111129639Srwatson error = NFSERR_AUTHERR | AUTH_TOOWEAK; 111236534Speter } 111336534Speter } 111436534Speter#endif 11151541Srgrimes /* 11161541Srgrimes * Check/setup credentials. 11171541Srgrimes */ 111883651Speter if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 11191541Srgrimes cred->cr_uid = credanon->cr_uid; 11201541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 11211541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 11223664Sphk cred->cr_ngroups = i; 11231541Srgrimes } 11241541Srgrimes if (exflags & MNT_EXRDONLY) 11251541Srgrimes *rdonlyp = 1; 11261541Srgrimes else 11271541Srgrimes *rdonlyp = 0; 11287969Sdyson 11291541Srgrimes if (!lockflag) 113083366Sjulian VOP_UNLOCK(*vpp, 0, td); 1131129639Srwatsonout: 1132157325Sjeff vfs_rel(mp); 1133157325Sjeff VFS_UNLOCK_GIANT(vfslocked); 1134129639Srwatson NFSD_LOCK(); 1135129639Srwatson return (error); 11361541Srgrimes} 11371541Srgrimes 113827446Sdfr 113927446Sdfr/* 114027446Sdfr * WebNFS: check if a filehandle is a public filehandle. For v3, this 114127446Sdfr * means a length of 0, for v2 it means all zeroes. nfsm_srvmtofh has 114227446Sdfr * transformed this to all zeroes in both cases, so check for it. 114327446Sdfr */ 114427446Sdfrint 114583651Speternfs_ispublicfh(fhandle_t *fhp) 114627446Sdfr{ 114727446Sdfr char *cp = (char *)fhp; 114827446Sdfr int i; 114927446Sdfr 1150129639Srwatson NFSD_LOCK_DONTCARE(); 1151129639Srwatson 115227446Sdfr for (i = 0; i < NFSX_V3FH; i++) 115327446Sdfr if (*cp++ != 0) 115427446Sdfr return (FALSE); 115527446Sdfr return (TRUE); 115627446Sdfr} 115783651Speter 11581541Srgrimes/* 11591541Srgrimes * This function compares two net addresses by family and returns TRUE 11601541Srgrimes * if they are the same host. 11611541Srgrimes * If there is any doubt, return FALSE. 11621541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 11631541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 11641541Srgrimes */ 11651549Srgrimesint 116683651Speternetaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam) 11671541Srgrimes{ 116883651Speter struct sockaddr_in *inetaddr; 11691541Srgrimes 1170129639Srwatson NFSD_LOCK_DONTCARE(); 1171129639Srwatson 11721541Srgrimes switch (family) { 11731541Srgrimes case AF_INET: 117428270Swollman inetaddr = (struct sockaddr_in *)nam; 11751541Srgrimes if (inetaddr->sin_family == AF_INET && 11761541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 11771541Srgrimes return (1); 11781541Srgrimes break; 1179100134Salfred#ifdef INET6 1180100134Salfred case AF_INET6: 1181100134Salfred { 1182100134Salfred register struct sockaddr_in6 *inet6addr1, *inet6addr2; 1183100134Salfred 1184100134Salfred inet6addr1 = (struct sockaddr_in6 *)nam; 1185100134Salfred inet6addr2 = (struct sockaddr_in6 *)haddr->had_nam; 1186100134Salfred /* XXX - should test sin6_scope_id ? */ 1187100134Salfred if (inet6addr1->sin6_family == AF_INET6 && 1188100134Salfred IN6_ARE_ADDR_EQUAL(&inet6addr1->sin6_addr, 1189100134Salfred &inet6addr2->sin6_addr)) 1190100134Salfred return (1); 1191100134Salfred break; 1192100134Salfred } 1193100134Salfred#endif 11941541Srgrimes default: 11951541Srgrimes break; 11961541Srgrimes }; 11971541Srgrimes return (0); 11981541Srgrimes} 11995455Sdg 12009336Sdfr/* 12019336Sdfr * Map errnos to NFS error numbers. For Version 3 also filter out error 12029336Sdfr * numbers not specified for the associated procedure. 12039336Sdfr */ 12045455Sdgint 120583651Speternfsrv_errmap(struct nfsrv_descript *nd, int err) 12069336Sdfr{ 1207129639Srwatson const short *defaulterrp, *errp; 1208102236Sphk int e; 12099336Sdfr 1210129639Srwatson NFSD_LOCK_DONTCARE(); 1211129639Srwatson 12129336Sdfr if (nd->nd_flag & ND_NFSV3) { 12139336Sdfr if (nd->nd_procnum <= NFSPROC_COMMIT) { 12149336Sdfr errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum]; 12159336Sdfr while (*++errp) { 12169336Sdfr if (*errp == err) 12179336Sdfr return (err); 12189336Sdfr else if (*errp > err) 12199336Sdfr break; 12209336Sdfr } 12219336Sdfr return ((int)*defaulterrp); 12229336Sdfr } else 12239336Sdfr return (err & 0xffff); 12249336Sdfr } 1225102236Sphk e = 0; 12269336Sdfr if (err <= ELAST) 1227102236Sphk e = nfsrv_v2errmap[err - 1]; 1228102236Sphk if (e != 0) 1229102236Sphk return (e); 12309336Sdfr return (NFSERR_IO); 12319336Sdfr} 12329336Sdfr 123336503Speter/* 123436503Speter * Sort the group list in increasing numerical order. 123536503Speter * (Insertion sort by Chris Torek, who was grossed out by the bubble sort 123636503Speter * that used to be here.) 123736503Speter */ 123836503Spetervoid 123983651Speternfsrvw_sort(gid_t *list, int num) 124036503Speter{ 124183651Speter int i, j; 124236503Speter gid_t v; 124336503Speter 1244129639Srwatson NFSD_LOCK_DONTCARE(); 1245129639Srwatson 124636503Speter /* Insertion sort. */ 124736503Speter for (i = 1; i < num; i++) { 124836503Speter v = list[i]; 124936503Speter /* find correct slot for value v, moving others up */ 125036503Speter for (j = i; --j >= 0 && v < list[j];) 125136503Speter list[j + 1] = list[j]; 125236503Speter list[j + 1] = v; 125336503Speter } 125436503Speter} 125536503Speter 125636503Speter/* 125736503Speter * copy credentials making sure that the result can be compared with bcmp(). 125836503Speter */ 125936503Spetervoid 126083651Speternfsrv_setcred(struct ucred *incred, struct ucred *outcred) 126136503Speter{ 126283651Speter int i; 126336503Speter 1264129639Srwatson NFSD_LOCK_DONTCARE(); 1265129639Srwatson 126636503Speter bzero((caddr_t)outcred, sizeof (struct ucred)); 1267150634Sjhb refcount_init(&outcred->cr_ref, 1); 126836503Speter outcred->cr_uid = incred->cr_uid; 126936503Speter outcred->cr_ngroups = incred->cr_ngroups; 127036503Speter for (i = 0; i < incred->cr_ngroups; i++) 127136503Speter outcred->cr_groups[i] = incred->cr_groups[i]; 127236503Speter nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups); 127336503Speter} 127483651Speter 127583651Speter/* 127683651Speter * Helper functions for macros. 127783651Speter */ 127883651Speter 127983651Spetervoid 128088091Siedowsenfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos) 128183651Speter{ 128288091Siedowse u_int32_t *tl; 128383651Speter 1284129639Srwatson NFSD_LOCK_DONTCARE(); 1285129639Srwatson 128683651Speter if (v3) { 128788091Siedowse tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 128888091Siedowse *tl++ = txdr_unsigned(NFSX_V3FH); 128988091Siedowse bcopy(f, tl, NFSX_V3FH); 129083651Speter } else { 129188091Siedowse tl = nfsm_build_xx(NFSX_V2FH, mb, bpos); 129288091Siedowse bcopy(f, tl, NFSX_V2FH); 129383651Speter } 129483651Speter} 129583651Speter 129683651Spetervoid 129788091Siedowsenfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos) 129883651Speter{ 129988091Siedowse u_int32_t *tl; 130084002Speter 130188091Siedowse tl = nfsm_build_xx(2 * NFSX_UNSIGNED + NFSX_V3FH, mb, bpos); 130289094Smsmith *tl++ = nfsrv_nfs_true; 130388091Siedowse *tl++ = txdr_unsigned(NFSX_V3FH); 130488091Siedowse bcopy(f, tl, NFSX_V3FH); 130583651Speter} 130683651Speter 130783651Speterint 130888091Siedowsenfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 130983651Speter{ 131088091Siedowse u_int32_t *tl; 131183651Speter 1312129639Srwatson NFSD_LOCK_DONTCARE(); 1313129639Srwatson 1314140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 131588091Siedowse if (tl == NULL) 131684057Speter return EBADRPC; 131788091Siedowse *s = fxdr_unsigned(int32_t, *tl); 131883651Speter if (*s > m || *s <= 0) 131983651Speter return EBADRPC; 132083651Speter return 0; 132183651Speter} 132283651Speter 132383651Speterint 1324106264Sjeffnfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos) 132583651Speter{ 132688091Siedowse u_int32_t *tl; 132783651Speter 1328129639Srwatson NFSD_LOCK_DONTCARE(); 1329129639Srwatson 1330140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 133188091Siedowse if (tl == NULL) 133284057Speter return EBADRPC; 133388091Siedowse *s = fxdr_unsigned(int32_t, *tl); 1334106264Sjeff if (*s > m) 133583651Speter return NFSERR_NAMETOL; 133683651Speter if (*s <= 0) 133783651Speter return EBADRPC; 133883651Speter return 0; 133983651Speter} 134083651Speter 134183651Spetervoid 134283651Speternfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp, 1343129639Srwatson char **bp, char **be, caddr_t bpos, int droplock) 134483651Speter{ 134583651Speter struct mbuf *nmp; 134683651Speter 1347129639Srwatson NFSD_LOCK_DONTCARE(); 1348129639Srwatson 1349129639Srwatson if (droplock) 1350129639Srwatson NFSD_LOCK_ASSERT(); 1351129639Srwatson else 1352129639Srwatson NFSD_UNLOCK_ASSERT(); 1353129639Srwatson 135483651Speter if (*bp >= *be) { 135583651Speter if (*mp == mb) 135683651Speter (*mp)->m_len += *bp - bpos; 1357129639Srwatson if (droplock) 1358129639Srwatson NFSD_UNLOCK(); 1359111119Simp MGET(nmp, M_TRYWAIT, MT_DATA); 1360111119Simp MCLGET(nmp, M_TRYWAIT); 1361129639Srwatson if (droplock) 1362129639Srwatson NFSD_LOCK(); 136383651Speter nmp->m_len = NFSMSIZ(nmp); 136483651Speter (*mp)->m_next = nmp; 136583651Speter *mp = nmp; 136683651Speter *bp = mtod(*mp, caddr_t); 136783651Speter *be = *bp + (*mp)->m_len; 136883651Speter } 136983651Speter *tl = (u_int32_t *)*bp; 137083651Speter} 137183651Speter 137283651Speterint 137388091Siedowsenfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md, 137488091Siedowse caddr_t *dpos) 137583651Speter{ 137688091Siedowse u_int32_t *tl; 137783651Speter int fhlen; 137883651Speter 1379129639Srwatson NFSD_LOCK_DONTCARE(); 1380129639Srwatson 138183651Speter if (nfsd->nd_flag & ND_NFSV3) { 1382140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 138388091Siedowse if (tl == NULL) 138484057Speter return EBADRPC; 138588091Siedowse fhlen = fxdr_unsigned(int, *tl); 138683651Speter if (fhlen != 0 && fhlen != NFSX_V3FH) 138783651Speter return EBADRPC; 138883651Speter } else { 138983651Speter fhlen = NFSX_V2FH; 139083651Speter } 139183651Speter if (fhlen != 0) { 1392140495Sps tl = nfsm_dissect_xx_nonblock(fhlen, md, dpos); 139388091Siedowse if (tl == NULL) 139484057Speter return EBADRPC; 139588091Siedowse bcopy((caddr_t)tl, (caddr_t)(f), fhlen); 139683651Speter } else { 139783651Speter bzero((caddr_t)(f), NFSX_V3FH); 139883651Speter } 139983651Speter return 0; 140083651Speter} 140183651Speter 140283651Speterint 140388091Siedowsenfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos) 140483651Speter{ 140588091Siedowse u_int32_t *tl; 1406157391Scel int toclient = 0; 140783651Speter 1408129639Srwatson NFSD_LOCK_DONTCARE(); 1409129639Srwatson 1410140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 141188091Siedowse if (tl == NULL) 141284057Speter return EBADRPC; 141389094Smsmith if (*tl == nfsrv_nfs_true) { 1414140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 141588091Siedowse if (tl == NULL) 141684057Speter return EBADRPC; 141788091Siedowse (a)->va_mode = nfstov_mode(*tl); 141883651Speter } 1419140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 142088091Siedowse if (tl == NULL) 142184057Speter return EBADRPC; 142289094Smsmith if (*tl == nfsrv_nfs_true) { 1423140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 142488091Siedowse if (tl == NULL) 142584057Speter return EBADRPC; 142688091Siedowse (a)->va_uid = fxdr_unsigned(uid_t, *tl); 142783651Speter } 1428140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 142988091Siedowse if (tl == NULL) 143084057Speter return EBADRPC; 143189094Smsmith if (*tl == nfsrv_nfs_true) { 1432140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 143388091Siedowse if (tl == NULL) 143484057Speter return EBADRPC; 143588091Siedowse (a)->va_gid = fxdr_unsigned(gid_t, *tl); 143683651Speter } 1437140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 143888091Siedowse if (tl == NULL) 143984057Speter return EBADRPC; 144089094Smsmith if (*tl == nfsrv_nfs_true) { 1441140495Sps tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 144288091Siedowse if (tl == NULL) 144384057Speter return EBADRPC; 144488091Siedowse (a)->va_size = fxdr_hyper(tl); 144583651Speter } 1446140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 144788091Siedowse if (tl == NULL) 144884057Speter return EBADRPC; 144988091Siedowse switch (fxdr_unsigned(int, *tl)) { 145083651Speter case NFSV3SATTRTIME_TOCLIENT: 1451140495Sps tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 145288091Siedowse if (tl == NULL) 145384057Speter return EBADRPC; 145488091Siedowse fxdr_nfsv3time(tl, &(a)->va_atime); 1455157391Scel toclient = 1; 145683651Speter break; 145783651Speter case NFSV3SATTRTIME_TOSERVER: 145883651Speter getnanotime(&(a)->va_atime); 1459157391Scel a->va_vaflags |= VA_UTIMES_NULL; 146083651Speter break; 146183651Speter } 1462140495Sps tl = nfsm_dissect_xx_nonblock(NFSX_UNSIGNED, md, dpos); 146388091Siedowse if (tl == NULL) 146484057Speter return EBADRPC; 146588091Siedowse switch (fxdr_unsigned(int, *tl)) { 146683651Speter case NFSV3SATTRTIME_TOCLIENT: 1467140495Sps tl = nfsm_dissect_xx_nonblock(2 * NFSX_UNSIGNED, md, dpos); 146888091Siedowse if (tl == NULL) 146984057Speter return EBADRPC; 147088091Siedowse fxdr_nfsv3time(tl, &(a)->va_mtime); 1471157391Scel a->va_vaflags &= ~VA_UTIMES_NULL; 147283651Speter break; 147383651Speter case NFSV3SATTRTIME_TOSERVER: 147483651Speter getnanotime(&(a)->va_mtime); 1475157391Scel if (toclient == 0) 1476157391Scel a->va_vaflags |= VA_UTIMES_NULL; 147783651Speter break; 147883651Speter } 147983651Speter return 0; 148083651Speter} 1481