nfs_srvsubs.c revision 1549
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1989, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * This code is derived from software contributed to Berkeley by 61541Srgrimes * Rick Macklem at The University of Guelph. 71541Srgrimes * 81541Srgrimes * Redistribution and use in source and binary forms, with or without 91541Srgrimes * modification, are permitted provided that the following conditions 101541Srgrimes * are met: 111541Srgrimes * 1. Redistributions of source code must retain the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer. 131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141541Srgrimes * notice, this list of conditions and the following disclaimer in the 151541Srgrimes * documentation and/or other materials provided with the distribution. 161541Srgrimes * 3. All advertising materials mentioning features or use of this software 171541Srgrimes * must display the following acknowledgement: 181541Srgrimes * This product includes software developed by the University of 191541Srgrimes * California, Berkeley and its contributors. 201541Srgrimes * 4. Neither the name of the University nor the names of its contributors 211541Srgrimes * may be used to endorse or promote products derived from this software 221541Srgrimes * without specific prior written permission. 231541Srgrimes * 241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341541Srgrimes * SUCH DAMAGE. 351541Srgrimes * 361541Srgrimes * @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94 371541Srgrimes */ 381541Srgrimes 391541Srgrimes/* 401541Srgrimes * These functions support the macros and help fiddle mbuf chains for 411541Srgrimes * the nfs op functions. They do things like create the rpc header and 421541Srgrimes * copy data between mbuf chains and uio lists. 431541Srgrimes */ 441541Srgrimes#include <sys/param.h> 451541Srgrimes#include <sys/proc.h> 461541Srgrimes#include <sys/systm.h> 471541Srgrimes#include <sys/kernel.h> 481541Srgrimes#include <sys/mount.h> 491541Srgrimes#include <sys/vnode.h> 501541Srgrimes#include <sys/namei.h> 511541Srgrimes#include <sys/mbuf.h> 521541Srgrimes#include <sys/socket.h> 531541Srgrimes#include <sys/stat.h> 541541Srgrimes 551541Srgrimes#include <nfs/rpcv2.h> 561541Srgrimes#include <nfs/nfsv2.h> 571541Srgrimes#include <nfs/nfsnode.h> 581541Srgrimes#include <nfs/nfs.h> 591541Srgrimes#include <nfs/xdr_subs.h> 601541Srgrimes#include <nfs/nfsm_subs.h> 611541Srgrimes#include <nfs/nfsmount.h> 621541Srgrimes#include <nfs/nqnfs.h> 631541Srgrimes#include <nfs/nfsrtt.h> 641541Srgrimes 651541Srgrimes#include <miscfs/specfs/specdev.h> 661541Srgrimes 671541Srgrimes#include <netinet/in.h> 681541Srgrimes#ifdef ISO 691541Srgrimes#include <netiso/iso.h> 701541Srgrimes#endif 711541Srgrimes 721541Srgrimes#define TRUE 1 731541Srgrimes#define FALSE 0 741541Srgrimes 751541Srgrimes/* 761541Srgrimes * Data items converted to xdr at startup, since they are constant 771541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 781541Srgrimes */ 791541Srgrimesu_long nfs_procids[NFS_NPROCS]; 801541Srgrimesu_long nfs_xdrneg1; 811541Srgrimesu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 821541Srgrimes rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred, 831541Srgrimes rpc_auth_kerb; 841541Srgrimesu_long nfs_vers, nfs_prog, nfs_true, nfs_false; 851541Srgrimes 861541Srgrimes/* And other global data */ 871541Srgrimesstatic u_long nfs_xid = 0; 881541Srgrimesenum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 891541Srgrimesextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 901541Srgrimesextern struct nfsreq nfsreqh; 911541Srgrimesextern int nqnfs_piggy[NFS_NPROCS]; 921541Srgrimesextern struct nfsrtt nfsrtt; 931541Srgrimesextern time_t nqnfsstarttime; 941541Srgrimesextern u_long nqnfs_prog, nqnfs_vers; 951541Srgrimesextern int nqsrv_clockskew; 961541Srgrimesextern int nqsrv_writeslack; 971541Srgrimesextern int nqsrv_maxlease; 981541Srgrimes 991541Srgrimes/* 1001541Srgrimes * Create the header for an rpc request packet 1011541Srgrimes * The hsiz is the size of the rest of the nfs request header. 1021541Srgrimes * (just used to decide if a cluster is a good idea) 1031541Srgrimes */ 1041541Srgrimesstruct mbuf * 1051541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp) 1061541Srgrimes struct vnode *vp; 1071541Srgrimes u_long procid; 1081541Srgrimes int hsiz; 1091541Srgrimes caddr_t *bposp; 1101541Srgrimes{ 1111541Srgrimes register struct mbuf *mb; 1121541Srgrimes register u_long *tl; 1131541Srgrimes register caddr_t bpos; 1141541Srgrimes struct mbuf *mb2; 1151541Srgrimes struct nfsmount *nmp; 1161541Srgrimes int nqflag; 1171541Srgrimes 1181541Srgrimes MGET(mb, M_WAIT, MT_DATA); 1191541Srgrimes if (hsiz >= MINCLSIZE) 1201541Srgrimes MCLGET(mb, M_WAIT); 1211541Srgrimes mb->m_len = 0; 1221541Srgrimes bpos = mtod(mb, caddr_t); 1231541Srgrimes 1241541Srgrimes /* 1251541Srgrimes * For NQNFS, add lease request. 1261541Srgrimes */ 1271541Srgrimes if (vp) { 1281541Srgrimes nmp = VFSTONFS(vp->v_mount); 1291541Srgrimes if (nmp->nm_flag & NFSMNT_NQNFS) { 1301541Srgrimes nqflag = NQNFS_NEEDLEASE(vp, procid); 1311541Srgrimes if (nqflag) { 1321541Srgrimes nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 1331541Srgrimes *tl++ = txdr_unsigned(nqflag); 1341541Srgrimes *tl = txdr_unsigned(nmp->nm_leaseterm); 1351541Srgrimes } else { 1361541Srgrimes nfsm_build(tl, u_long *, NFSX_UNSIGNED); 1371541Srgrimes *tl = 0; 1381541Srgrimes } 1391541Srgrimes } 1401541Srgrimes } 1411541Srgrimes /* Finally, return values */ 1421541Srgrimes *bposp = bpos; 1431541Srgrimes return (mb); 1441541Srgrimes} 1451541Srgrimes 1461541Srgrimes/* 1471541Srgrimes * Build the RPC header and fill in the authorization info. 1481541Srgrimes * The authorization string argument is only used when the credentials 1491541Srgrimes * come from outside of the kernel. 1501541Srgrimes * Returns the head of the mbuf list. 1511541Srgrimes */ 1521541Srgrimesstruct mbuf * 1531541Srgrimesnfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, 1541541Srgrimes mrest_len, mbp, xidp) 1551541Srgrimes register struct ucred *cr; 1561541Srgrimes int nqnfs; 1571541Srgrimes int procid; 1581541Srgrimes int auth_type; 1591541Srgrimes int auth_len; 1601541Srgrimes char *auth_str; 1611541Srgrimes struct mbuf *mrest; 1621541Srgrimes int mrest_len; 1631541Srgrimes struct mbuf **mbp; 1641541Srgrimes u_long *xidp; 1651541Srgrimes{ 1661541Srgrimes register struct mbuf *mb; 1671541Srgrimes register u_long *tl; 1681541Srgrimes register caddr_t bpos; 1691541Srgrimes register int i; 1701541Srgrimes struct mbuf *mreq, *mb2; 1711541Srgrimes int siz, grpsiz, authsiz; 1721541Srgrimes 1731541Srgrimes authsiz = nfsm_rndup(auth_len); 1741541Srgrimes if (auth_type == RPCAUTH_NQNFS) 1751541Srgrimes authsiz += 2 * NFSX_UNSIGNED; 1761541Srgrimes MGETHDR(mb, M_WAIT, MT_DATA); 1771541Srgrimes if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) { 1781541Srgrimes MCLGET(mb, M_WAIT); 1791541Srgrimes } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) { 1801541Srgrimes MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED); 1811541Srgrimes } else { 1821541Srgrimes MH_ALIGN(mb, 8*NFSX_UNSIGNED); 1831541Srgrimes } 1841541Srgrimes mb->m_len = 0; 1851541Srgrimes mreq = mb; 1861541Srgrimes bpos = mtod(mb, caddr_t); 1871541Srgrimes 1881541Srgrimes /* 1891541Srgrimes * First the RPC header. 1901541Srgrimes */ 1911541Srgrimes nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED); 1921541Srgrimes if (++nfs_xid == 0) 1931541Srgrimes nfs_xid++; 1941541Srgrimes *tl++ = *xidp = txdr_unsigned(nfs_xid); 1951541Srgrimes *tl++ = rpc_call; 1961541Srgrimes *tl++ = rpc_vers; 1971541Srgrimes if (nqnfs) { 1981541Srgrimes *tl++ = txdr_unsigned(NQNFS_PROG); 1991541Srgrimes *tl++ = txdr_unsigned(NQNFS_VER1); 2001541Srgrimes } else { 2011541Srgrimes *tl++ = txdr_unsigned(NFS_PROG); 2021541Srgrimes *tl++ = txdr_unsigned(NFS_VER2); 2031541Srgrimes } 2041541Srgrimes *tl++ = txdr_unsigned(procid); 2051541Srgrimes 2061541Srgrimes /* 2071541Srgrimes * And then the authorization cred. 2081541Srgrimes */ 2091541Srgrimes *tl++ = txdr_unsigned(auth_type); 2101541Srgrimes *tl = txdr_unsigned(authsiz); 2111541Srgrimes switch (auth_type) { 2121541Srgrimes case RPCAUTH_UNIX: 2131541Srgrimes nfsm_build(tl, u_long *, auth_len); 2141541Srgrimes *tl++ = 0; /* stamp ?? */ 2151541Srgrimes *tl++ = 0; /* NULL hostname */ 2161541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 2171541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[0]); 2181541Srgrimes grpsiz = (auth_len >> 2) - 5; 2191541Srgrimes *tl++ = txdr_unsigned(grpsiz); 2201541Srgrimes for (i = 1; i <= grpsiz; i++) 2211541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[i]); 2221541Srgrimes break; 2231541Srgrimes case RPCAUTH_NQNFS: 2241541Srgrimes nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 2251541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 2261541Srgrimes *tl = txdr_unsigned(auth_len); 2271541Srgrimes siz = auth_len; 2281541Srgrimes while (siz > 0) { 2291541Srgrimes if (M_TRAILINGSPACE(mb) == 0) { 2301541Srgrimes MGET(mb2, M_WAIT, MT_DATA); 2311541Srgrimes if (siz >= MINCLSIZE) 2321541Srgrimes MCLGET(mb2, M_WAIT); 2331541Srgrimes mb->m_next = mb2; 2341541Srgrimes mb = mb2; 2351541Srgrimes mb->m_len = 0; 2361541Srgrimes bpos = mtod(mb, caddr_t); 2371541Srgrimes } 2381541Srgrimes i = min(siz, M_TRAILINGSPACE(mb)); 2391541Srgrimes bcopy(auth_str, bpos, i); 2401541Srgrimes mb->m_len += i; 2411541Srgrimes auth_str += i; 2421541Srgrimes bpos += i; 2431541Srgrimes siz -= i; 2441541Srgrimes } 2451541Srgrimes if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 2461541Srgrimes for (i = 0; i < siz; i++) 2471541Srgrimes *bpos++ = '\0'; 2481541Srgrimes mb->m_len += siz; 2491541Srgrimes } 2501541Srgrimes break; 2511541Srgrimes }; 2521541Srgrimes nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 2531541Srgrimes *tl++ = txdr_unsigned(RPCAUTH_NULL); 2541541Srgrimes *tl = 0; 2551541Srgrimes mb->m_next = mrest; 2561541Srgrimes mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len; 2571541Srgrimes mreq->m_pkthdr.rcvif = (struct ifnet *)0; 2581541Srgrimes *mbp = mb; 2591541Srgrimes return (mreq); 2601541Srgrimes} 2611541Srgrimes 2621541Srgrimes/* 2631541Srgrimes * copies mbuf chain to the uio scatter/gather list 2641541Srgrimes */ 2651549Srgrimesint 2661541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos) 2671541Srgrimes struct mbuf **mrep; 2681541Srgrimes register struct uio *uiop; 2691541Srgrimes int siz; 2701541Srgrimes caddr_t *dpos; 2711541Srgrimes{ 2721541Srgrimes register char *mbufcp, *uiocp; 2731541Srgrimes register int xfer, left, len; 2741541Srgrimes register struct mbuf *mp; 2751541Srgrimes long uiosiz, rem; 2761541Srgrimes int error = 0; 2771541Srgrimes 2781541Srgrimes mp = *mrep; 2791541Srgrimes mbufcp = *dpos; 2801541Srgrimes len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 2811541Srgrimes rem = nfsm_rndup(siz)-siz; 2821541Srgrimes while (siz > 0) { 2831541Srgrimes if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 2841541Srgrimes return (EFBIG); 2851541Srgrimes left = uiop->uio_iov->iov_len; 2861541Srgrimes uiocp = uiop->uio_iov->iov_base; 2871541Srgrimes if (left > siz) 2881541Srgrimes left = siz; 2891541Srgrimes uiosiz = left; 2901541Srgrimes while (left > 0) { 2911541Srgrimes while (len == 0) { 2921541Srgrimes mp = mp->m_next; 2931541Srgrimes if (mp == NULL) 2941541Srgrimes return (EBADRPC); 2951541Srgrimes mbufcp = mtod(mp, caddr_t); 2961541Srgrimes len = mp->m_len; 2971541Srgrimes } 2981541Srgrimes xfer = (left > len) ? len : left; 2991541Srgrimes#ifdef notdef 3001541Srgrimes /* Not Yet.. */ 3011541Srgrimes if (uiop->uio_iov->iov_op != NULL) 3021541Srgrimes (*(uiop->uio_iov->iov_op)) 3031541Srgrimes (mbufcp, uiocp, xfer); 3041541Srgrimes else 3051541Srgrimes#endif 3061541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 3071541Srgrimes bcopy(mbufcp, uiocp, xfer); 3081541Srgrimes else 3091541Srgrimes copyout(mbufcp, uiocp, xfer); 3101541Srgrimes left -= xfer; 3111541Srgrimes len -= xfer; 3121541Srgrimes mbufcp += xfer; 3131541Srgrimes uiocp += xfer; 3141541Srgrimes uiop->uio_offset += xfer; 3151541Srgrimes uiop->uio_resid -= xfer; 3161541Srgrimes } 3171541Srgrimes if (uiop->uio_iov->iov_len <= siz) { 3181541Srgrimes uiop->uio_iovcnt--; 3191541Srgrimes uiop->uio_iov++; 3201541Srgrimes } else { 3211541Srgrimes uiop->uio_iov->iov_base += uiosiz; 3221541Srgrimes uiop->uio_iov->iov_len -= uiosiz; 3231541Srgrimes } 3241541Srgrimes siz -= uiosiz; 3251541Srgrimes } 3261541Srgrimes *dpos = mbufcp; 3271541Srgrimes *mrep = mp; 3281541Srgrimes if (rem > 0) { 3291541Srgrimes if (len < rem) 3301541Srgrimes error = nfs_adv(mrep, dpos, rem, len); 3311541Srgrimes else 3321541Srgrimes *dpos += rem; 3331541Srgrimes } 3341541Srgrimes return (error); 3351541Srgrimes} 3361541Srgrimes 3371541Srgrimes/* 3381541Srgrimes * copies a uio scatter/gather list to an mbuf chain... 3391541Srgrimes */ 3401549Srgrimesint 3411541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos) 3421541Srgrimes register struct uio *uiop; 3431541Srgrimes struct mbuf **mq; 3441541Srgrimes int siz; 3451541Srgrimes caddr_t *bpos; 3461541Srgrimes{ 3471541Srgrimes register char *uiocp; 3481541Srgrimes register struct mbuf *mp, *mp2; 3491541Srgrimes register int xfer, left, mlen; 3501541Srgrimes int uiosiz, clflg, rem; 3511541Srgrimes char *cp; 3521541Srgrimes 3531541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 3541541Srgrimes clflg = 1; 3551541Srgrimes else 3561541Srgrimes clflg = 0; 3571541Srgrimes rem = nfsm_rndup(siz)-siz; 3581541Srgrimes mp = mp2 = *mq; 3591541Srgrimes while (siz > 0) { 3601541Srgrimes if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 3611541Srgrimes return (EINVAL); 3621541Srgrimes left = uiop->uio_iov->iov_len; 3631541Srgrimes uiocp = uiop->uio_iov->iov_base; 3641541Srgrimes if (left > siz) 3651541Srgrimes left = siz; 3661541Srgrimes uiosiz = left; 3671541Srgrimes while (left > 0) { 3681541Srgrimes mlen = M_TRAILINGSPACE(mp); 3691541Srgrimes if (mlen == 0) { 3701541Srgrimes MGET(mp, M_WAIT, MT_DATA); 3711541Srgrimes if (clflg) 3721541Srgrimes MCLGET(mp, M_WAIT); 3731541Srgrimes mp->m_len = 0; 3741541Srgrimes mp2->m_next = mp; 3751541Srgrimes mp2 = mp; 3761541Srgrimes mlen = M_TRAILINGSPACE(mp); 3771541Srgrimes } 3781541Srgrimes xfer = (left > mlen) ? mlen : left; 3791541Srgrimes#ifdef notdef 3801541Srgrimes /* Not Yet.. */ 3811541Srgrimes if (uiop->uio_iov->iov_op != NULL) 3821541Srgrimes (*(uiop->uio_iov->iov_op)) 3831541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 3841541Srgrimes else 3851541Srgrimes#endif 3861541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 3871541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 3881541Srgrimes else 3891541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 3901541Srgrimes mp->m_len += xfer; 3911541Srgrimes left -= xfer; 3921541Srgrimes uiocp += xfer; 3931541Srgrimes uiop->uio_offset += xfer; 3941541Srgrimes uiop->uio_resid -= xfer; 3951541Srgrimes } 3961541Srgrimes if (uiop->uio_iov->iov_len <= siz) { 3971541Srgrimes uiop->uio_iovcnt--; 3981541Srgrimes uiop->uio_iov++; 3991541Srgrimes } else { 4001541Srgrimes uiop->uio_iov->iov_base += uiosiz; 4011541Srgrimes uiop->uio_iov->iov_len -= uiosiz; 4021541Srgrimes } 4031541Srgrimes siz -= uiosiz; 4041541Srgrimes } 4051541Srgrimes if (rem > 0) { 4061541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 4071541Srgrimes MGET(mp, M_WAIT, MT_DATA); 4081541Srgrimes mp->m_len = 0; 4091541Srgrimes mp2->m_next = mp; 4101541Srgrimes } 4111541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 4121541Srgrimes for (left = 0; left < rem; left++) 4131541Srgrimes *cp++ = '\0'; 4141541Srgrimes mp->m_len += rem; 4151541Srgrimes *bpos = cp; 4161541Srgrimes } else 4171541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 4181541Srgrimes *mq = mp; 4191541Srgrimes return (0); 4201541Srgrimes} 4211541Srgrimes 4221541Srgrimes/* 4231541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous 4241541Srgrimes * pointed to by returned val. 4251541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 4261541Srgrimes * cases. (The macros use the vars. dpos and dpos2) 4271541Srgrimes */ 4281549Srgrimesint 4291541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2) 4301541Srgrimes struct mbuf **mdp; 4311541Srgrimes caddr_t *dposp; 4321541Srgrimes int siz; 4331541Srgrimes int left; 4341541Srgrimes caddr_t *cp2; 4351541Srgrimes{ 4361541Srgrimes register struct mbuf *mp, *mp2; 4371541Srgrimes register int siz2, xfer; 4381541Srgrimes register caddr_t p; 4391541Srgrimes 4401541Srgrimes mp = *mdp; 4411541Srgrimes while (left == 0) { 4421541Srgrimes *mdp = mp = mp->m_next; 4431541Srgrimes if (mp == NULL) 4441541Srgrimes return (EBADRPC); 4451541Srgrimes left = mp->m_len; 4461541Srgrimes *dposp = mtod(mp, caddr_t); 4471541Srgrimes } 4481541Srgrimes if (left >= siz) { 4491541Srgrimes *cp2 = *dposp; 4501541Srgrimes *dposp += siz; 4511541Srgrimes } else if (mp->m_next == NULL) { 4521541Srgrimes return (EBADRPC); 4531541Srgrimes } else if (siz > MHLEN) { 4541541Srgrimes panic("nfs S too big"); 4551541Srgrimes } else { 4561541Srgrimes MGET(mp2, M_WAIT, MT_DATA); 4571541Srgrimes mp2->m_next = mp->m_next; 4581541Srgrimes mp->m_next = mp2; 4591541Srgrimes mp->m_len -= left; 4601541Srgrimes mp = mp2; 4611541Srgrimes *cp2 = p = mtod(mp, caddr_t); 4621541Srgrimes bcopy(*dposp, p, left); /* Copy what was left */ 4631541Srgrimes siz2 = siz-left; 4641541Srgrimes p += left; 4651541Srgrimes mp2 = mp->m_next; 4661541Srgrimes /* Loop around copying up the siz2 bytes */ 4671541Srgrimes while (siz2 > 0) { 4681541Srgrimes if (mp2 == NULL) 4691541Srgrimes return (EBADRPC); 4701541Srgrimes xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 4711541Srgrimes if (xfer > 0) { 4721541Srgrimes bcopy(mtod(mp2, caddr_t), p, xfer); 4731541Srgrimes NFSMADV(mp2, xfer); 4741541Srgrimes mp2->m_len -= xfer; 4751541Srgrimes p += xfer; 4761541Srgrimes siz2 -= xfer; 4771541Srgrimes } 4781541Srgrimes if (siz2 > 0) 4791541Srgrimes mp2 = mp2->m_next; 4801541Srgrimes } 4811541Srgrimes mp->m_len = siz; 4821541Srgrimes *mdp = mp2; 4831541Srgrimes *dposp = mtod(mp2, caddr_t); 4841541Srgrimes } 4851541Srgrimes return (0); 4861541Srgrimes} 4871541Srgrimes 4881541Srgrimes/* 4891541Srgrimes * Advance the position in the mbuf chain. 4901541Srgrimes */ 4911549Srgrimesint 4921541Srgrimesnfs_adv(mdp, dposp, offs, left) 4931541Srgrimes struct mbuf **mdp; 4941541Srgrimes caddr_t *dposp; 4951541Srgrimes int offs; 4961541Srgrimes int left; 4971541Srgrimes{ 4981541Srgrimes register struct mbuf *m; 4991541Srgrimes register int s; 5001541Srgrimes 5011541Srgrimes m = *mdp; 5021541Srgrimes s = left; 5031541Srgrimes while (s < offs) { 5041541Srgrimes offs -= s; 5051541Srgrimes m = m->m_next; 5061541Srgrimes if (m == NULL) 5071541Srgrimes return (EBADRPC); 5081541Srgrimes s = m->m_len; 5091541Srgrimes } 5101541Srgrimes *mdp = m; 5111541Srgrimes *dposp = mtod(m, caddr_t)+offs; 5121541Srgrimes return (0); 5131541Srgrimes} 5141541Srgrimes 5151541Srgrimes/* 5161541Srgrimes * Copy a string into mbufs for the hard cases... 5171541Srgrimes */ 5181549Srgrimesint 5191541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz) 5201541Srgrimes struct mbuf **mb; 5211541Srgrimes char **bpos; 5221541Srgrimes char *cp; 5231541Srgrimes long siz; 5241541Srgrimes{ 5251549Srgrimes register struct mbuf *m1 = 0, *m2; 5261541Srgrimes long left, xfer, len, tlen; 5271541Srgrimes u_long *tl; 5281541Srgrimes int putsize; 5291541Srgrimes 5301541Srgrimes putsize = 1; 5311541Srgrimes m2 = *mb; 5321541Srgrimes left = M_TRAILINGSPACE(m2); 5331541Srgrimes if (left > 0) { 5341541Srgrimes tl = ((u_long *)(*bpos)); 5351541Srgrimes *tl++ = txdr_unsigned(siz); 5361541Srgrimes putsize = 0; 5371541Srgrimes left -= NFSX_UNSIGNED; 5381541Srgrimes m2->m_len += NFSX_UNSIGNED; 5391541Srgrimes if (left > 0) { 5401541Srgrimes bcopy(cp, (caddr_t) tl, left); 5411541Srgrimes siz -= left; 5421541Srgrimes cp += left; 5431541Srgrimes m2->m_len += left; 5441541Srgrimes left = 0; 5451541Srgrimes } 5461541Srgrimes } 5471541Srgrimes /* Loop around adding mbufs */ 5481541Srgrimes while (siz > 0) { 5491541Srgrimes MGET(m1, M_WAIT, MT_DATA); 5501541Srgrimes if (siz > MLEN) 5511541Srgrimes MCLGET(m1, M_WAIT); 5521541Srgrimes m1->m_len = NFSMSIZ(m1); 5531541Srgrimes m2->m_next = m1; 5541541Srgrimes m2 = m1; 5551541Srgrimes tl = mtod(m1, u_long *); 5561541Srgrimes tlen = 0; 5571541Srgrimes if (putsize) { 5581541Srgrimes *tl++ = txdr_unsigned(siz); 5591541Srgrimes m1->m_len -= NFSX_UNSIGNED; 5601541Srgrimes tlen = NFSX_UNSIGNED; 5611541Srgrimes putsize = 0; 5621541Srgrimes } 5631541Srgrimes if (siz < m1->m_len) { 5641541Srgrimes len = nfsm_rndup(siz); 5651541Srgrimes xfer = siz; 5661541Srgrimes if (xfer < len) 5671541Srgrimes *(tl+(xfer>>2)) = 0; 5681541Srgrimes } else { 5691541Srgrimes xfer = len = m1->m_len; 5701541Srgrimes } 5711541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 5721541Srgrimes m1->m_len = len+tlen; 5731541Srgrimes siz -= xfer; 5741541Srgrimes cp += xfer; 5751541Srgrimes } 5761541Srgrimes *mb = m1; 5771541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 5781541Srgrimes return (0); 5791541Srgrimes} 5801541Srgrimes 5811541Srgrimes/* 5821541Srgrimes * Called once to initialize data structures... 5831541Srgrimes */ 5841549Srgrimesint 5851541Srgrimesnfs_init() 5861541Srgrimes{ 5871541Srgrimes register int i; 5881541Srgrimes 5891541Srgrimes nfsrtt.pos = 0; 5901541Srgrimes rpc_vers = txdr_unsigned(RPC_VER2); 5911541Srgrimes rpc_call = txdr_unsigned(RPC_CALL); 5921541Srgrimes rpc_reply = txdr_unsigned(RPC_REPLY); 5931541Srgrimes rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 5941541Srgrimes rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 5951541Srgrimes rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 5961541Srgrimes rpc_autherr = txdr_unsigned(RPC_AUTHERR); 5971541Srgrimes rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); 5981541Srgrimes rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 5991541Srgrimes rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); 6001541Srgrimes nfs_vers = txdr_unsigned(NFS_VER2); 6011541Srgrimes nfs_prog = txdr_unsigned(NFS_PROG); 6021541Srgrimes nfs_true = txdr_unsigned(TRUE); 6031541Srgrimes nfs_false = txdr_unsigned(FALSE); 6041541Srgrimes /* Loop thru nfs procids */ 6051541Srgrimes for (i = 0; i < NFS_NPROCS; i++) 6061541Srgrimes nfs_procids[i] = txdr_unsigned(i); 6071541Srgrimes /* Ensure async daemons disabled */ 6081541Srgrimes for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 6091541Srgrimes nfs_iodwant[i] = (struct proc *)0; 6101541Srgrimes TAILQ_INIT(&nfs_bufq); 6111541Srgrimes nfs_xdrneg1 = txdr_unsigned(-1); 6121541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 6131541Srgrimes nfsrv_init(0); /* Init server data structures */ 6141541Srgrimes nfsrv_initcache(); /* Init the server request cache */ 6151541Srgrimes 6161541Srgrimes /* 6171541Srgrimes * Initialize the nqnfs server stuff. 6181541Srgrimes */ 6191541Srgrimes if (nqnfsstarttime == 0) { 6201541Srgrimes nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 6211541Srgrimes + nqsrv_clockskew + nqsrv_writeslack; 6221541Srgrimes NQLOADNOVRAM(nqnfsstarttime); 6231541Srgrimes nqnfs_prog = txdr_unsigned(NQNFS_PROG); 6241541Srgrimes nqnfs_vers = txdr_unsigned(NQNFS_VER1); 6251541Srgrimes nqthead.th_head[0] = &nqthead; 6261541Srgrimes nqthead.th_head[1] = &nqthead; 6271541Srgrimes nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash); 6281541Srgrimes } 6291541Srgrimes 6301541Srgrimes /* 6311541Srgrimes * Initialize reply list and start timer 6321541Srgrimes */ 6331541Srgrimes nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 6341541Srgrimes nfs_timer(); 6351549Srgrimes 6361549Srgrimes return (0); 6371541Srgrimes} 6381541Srgrimes 6391541Srgrimes/* 6401541Srgrimes * Attribute cache routines. 6411541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 6421541Srgrimes * that are on the mbuf list 6431541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 6441541Srgrimes * error otherwise 6451541Srgrimes */ 6461541Srgrimes 6471541Srgrimes/* 6481541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 6491541Srgrimes * the values on the mbuf list and 6501541Srgrimes * Iff vap not NULL 6511541Srgrimes * copy the attributes to *vaper 6521541Srgrimes */ 6531549Srgrimesint 6541541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper) 6551541Srgrimes struct vnode **vpp; 6561541Srgrimes struct mbuf **mdp; 6571541Srgrimes caddr_t *dposp; 6581541Srgrimes struct vattr *vaper; 6591541Srgrimes{ 6601541Srgrimes register struct vnode *vp = *vpp; 6611541Srgrimes register struct vattr *vap; 6621541Srgrimes register struct nfsv2_fattr *fp; 6631541Srgrimes extern int (**spec_nfsv2nodeop_p)(); 6641541Srgrimes register struct nfsnode *np, *nq, **nhpp; 6651541Srgrimes register long t1; 6661541Srgrimes caddr_t dpos, cp2; 6671541Srgrimes int error = 0, isnq; 6681541Srgrimes struct mbuf *md; 6691541Srgrimes enum vtype vtyp; 6701541Srgrimes u_short vmode; 6711541Srgrimes long rdev; 6721541Srgrimes struct timespec mtime; 6731541Srgrimes struct vnode *nvp; 6741541Srgrimes 6751541Srgrimes md = *mdp; 6761541Srgrimes dpos = *dposp; 6771541Srgrimes t1 = (mtod(md, caddr_t) + md->m_len) - dpos; 6781541Srgrimes isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 6791541Srgrimes if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2)) 6801541Srgrimes return (error); 6811541Srgrimes fp = (struct nfsv2_fattr *)cp2; 6821541Srgrimes vtyp = nfstov_type(fp->fa_type); 6831541Srgrimes vmode = fxdr_unsigned(u_short, fp->fa_mode); 6841541Srgrimes if (vtyp == VNON || vtyp == VREG) 6851541Srgrimes vtyp = IFTOVT(vmode); 6861541Srgrimes if (isnq) { 6871541Srgrimes rdev = fxdr_unsigned(long, fp->fa_nqrdev); 6881541Srgrimes fxdr_nqtime(&fp->fa_nqmtime, &mtime); 6891541Srgrimes } else { 6901541Srgrimes rdev = fxdr_unsigned(long, fp->fa_nfsrdev); 6911541Srgrimes fxdr_nfstime(&fp->fa_nfsmtime, &mtime); 6921541Srgrimes } 6931541Srgrimes /* 6941541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 6951541Srgrimes * n_mtime fields. Check to see if it represents a special 6961541Srgrimes * device, and if so, check for a possible alias. Once the 6971541Srgrimes * correct vnode has been obtained, fill in the rest of the 6981541Srgrimes * information. 6991541Srgrimes */ 7001541Srgrimes np = VTONFS(vp); 7011541Srgrimes if (vp->v_type == VNON) { 7021541Srgrimes if (vtyp == VCHR && rdev == 0xffffffff) 7031541Srgrimes vp->v_type = vtyp = VFIFO; 7041541Srgrimes else 7051541Srgrimes vp->v_type = vtyp; 7061541Srgrimes if (vp->v_type == VFIFO) { 7071541Srgrimes#ifdef FIFO 7081541Srgrimes extern int (**fifo_nfsv2nodeop_p)(); 7091541Srgrimes vp->v_op = fifo_nfsv2nodeop_p; 7101541Srgrimes#else 7111541Srgrimes return (EOPNOTSUPP); 7121541Srgrimes#endif /* FIFO */ 7131541Srgrimes } 7141541Srgrimes if (vp->v_type == VCHR || vp->v_type == VBLK) { 7151541Srgrimes vp->v_op = spec_nfsv2nodeop_p; 7161541Srgrimes if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 7171541Srgrimes /* 7181541Srgrimes * Discard unneeded vnode, but save its nfsnode. 7191541Srgrimes */ 7201541Srgrimes if (nq = np->n_forw) 7211541Srgrimes nq->n_back = np->n_back; 7221541Srgrimes *np->n_back = nq; 7231541Srgrimes nvp->v_data = vp->v_data; 7241541Srgrimes vp->v_data = NULL; 7251541Srgrimes vp->v_op = spec_vnodeop_p; 7261541Srgrimes vrele(vp); 7271541Srgrimes vgone(vp); 7281541Srgrimes /* 7291541Srgrimes * Reinitialize aliased node. 7301541Srgrimes */ 7311541Srgrimes np->n_vnode = nvp; 7321541Srgrimes nhpp = (struct nfsnode **)nfs_hash(&np->n_fh); 7331541Srgrimes if (nq = *nhpp) 7341541Srgrimes nq->n_back = &np->n_forw; 7351541Srgrimes np->n_forw = nq; 7361541Srgrimes np->n_back = nhpp; 7371541Srgrimes *nhpp = np; 7381541Srgrimes *vpp = vp = nvp; 7391541Srgrimes } 7401541Srgrimes } 7411541Srgrimes np->n_mtime = mtime.ts_sec; 7421541Srgrimes } 7431541Srgrimes vap = &np->n_vattr; 7441541Srgrimes vap->va_type = vtyp; 7451541Srgrimes vap->va_mode = (vmode & 07777); 7461541Srgrimes vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 7471541Srgrimes vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 7481541Srgrimes vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 7491541Srgrimes vap->va_rdev = (dev_t)rdev; 7501541Srgrimes vap->va_mtime = mtime; 7511541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 7521541Srgrimes if (isnq) { 7531541Srgrimes fxdr_hyper(&fp->fa_nqsize, &vap->va_size); 7541541Srgrimes vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize); 7551541Srgrimes fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes); 7561541Srgrimes vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid); 7571541Srgrimes fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime); 7581541Srgrimes vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags); 7591541Srgrimes fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime); 7601541Srgrimes vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen); 7611541Srgrimes fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev); 7621541Srgrimes } else { 7631541Srgrimes vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize); 7641541Srgrimes vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize); 7651541Srgrimes vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE; 7661541Srgrimes vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid); 7671541Srgrimes fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime); 7681541Srgrimes vap->va_flags = 0; 7691541Srgrimes vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_nfsctime.nfs_sec); 7701541Srgrimes vap->va_ctime.ts_nsec = 0; 7711541Srgrimes vap->va_gen = fxdr_unsigned(u_long, fp->fa_nfsctime.nfs_usec); 7721541Srgrimes vap->va_filerev = 0; 7731541Srgrimes } 7741541Srgrimes if (vap->va_size != np->n_size) { 7751541Srgrimes if (vap->va_type == VREG) { 7761541Srgrimes if (np->n_flag & NMODIFIED) { 7771541Srgrimes if (vap->va_size < np->n_size) 7781541Srgrimes vap->va_size = np->n_size; 7791541Srgrimes else 7801541Srgrimes np->n_size = vap->va_size; 7811541Srgrimes } else 7821541Srgrimes np->n_size = vap->va_size; 7831541Srgrimes vnode_pager_setsize(vp, (u_long)np->n_size); 7841541Srgrimes } else 7851541Srgrimes np->n_size = vap->va_size; 7861541Srgrimes } 7871541Srgrimes np->n_attrstamp = time.tv_sec; 7881541Srgrimes *dposp = dpos; 7891541Srgrimes *mdp = md; 7901541Srgrimes if (vaper != NULL) { 7911541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 7921541Srgrimes#ifdef notdef 7931541Srgrimes if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size) 7941541Srgrimes if (np->n_size > vap->va_size) 7951541Srgrimes vaper->va_size = np->n_size; 7961541Srgrimes#endif 7971541Srgrimes if (np->n_flag & NCHG) { 7981541Srgrimes if (np->n_flag & NACC) { 7991541Srgrimes vaper->va_atime.ts_sec = np->n_atim.tv_sec; 8001541Srgrimes vaper->va_atime.ts_nsec = 8011541Srgrimes np->n_atim.tv_usec * 1000; 8021541Srgrimes } 8031541Srgrimes if (np->n_flag & NUPD) { 8041541Srgrimes vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 8051541Srgrimes vaper->va_mtime.ts_nsec = 8061541Srgrimes np->n_mtim.tv_usec * 1000; 8071541Srgrimes } 8081541Srgrimes } 8091541Srgrimes } 8101541Srgrimes return (0); 8111541Srgrimes} 8121541Srgrimes 8131541Srgrimes/* 8141541Srgrimes * Check the time stamp 8151541Srgrimes * If the cache is valid, copy contents to *vap and return 0 8161541Srgrimes * otherwise return an error 8171541Srgrimes */ 8181549Srgrimesint 8191541Srgrimesnfs_getattrcache(vp, vaper) 8201541Srgrimes register struct vnode *vp; 8211541Srgrimes struct vattr *vaper; 8221541Srgrimes{ 8231541Srgrimes register struct nfsnode *np = VTONFS(vp); 8241541Srgrimes register struct vattr *vap; 8251541Srgrimes 8261541Srgrimes if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) { 8271541Srgrimes if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 8281541Srgrimes nfsstats.attrcache_misses++; 8291541Srgrimes return (ENOENT); 8301541Srgrimes } 8311541Srgrimes } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 8321541Srgrimes nfsstats.attrcache_misses++; 8331541Srgrimes return (ENOENT); 8341541Srgrimes } 8351541Srgrimes nfsstats.attrcache_hits++; 8361541Srgrimes vap = &np->n_vattr; 8371541Srgrimes if (vap->va_size != np->n_size) { 8381541Srgrimes if (vap->va_type == VREG) { 8391541Srgrimes if (np->n_flag & NMODIFIED) { 8401541Srgrimes if (vap->va_size < np->n_size) 8411541Srgrimes vap->va_size = np->n_size; 8421541Srgrimes else 8431541Srgrimes np->n_size = vap->va_size; 8441541Srgrimes } else 8451541Srgrimes np->n_size = vap->va_size; 8461541Srgrimes vnode_pager_setsize(vp, (u_long)np->n_size); 8471541Srgrimes } else 8481541Srgrimes np->n_size = vap->va_size; 8491541Srgrimes } 8501541Srgrimes bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 8511541Srgrimes#ifdef notdef 8521541Srgrimes if ((np->n_flag & NMODIFIED) == 0) { 8531541Srgrimes np->n_size = vaper->va_size; 8541541Srgrimes vnode_pager_setsize(vp, (u_long)np->n_size); 8551541Srgrimes } else if (np->n_size > vaper->va_size) 8561541Srgrimes if (np->n_size > vaper->va_size) 8571541Srgrimes vaper->va_size = np->n_size; 8581541Srgrimes#endif 8591541Srgrimes if (np->n_flag & NCHG) { 8601541Srgrimes if (np->n_flag & NACC) { 8611541Srgrimes vaper->va_atime.ts_sec = np->n_atim.tv_sec; 8621541Srgrimes vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000; 8631541Srgrimes } 8641541Srgrimes if (np->n_flag & NUPD) { 8651541Srgrimes vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 8661541Srgrimes vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000; 8671541Srgrimes } 8681541Srgrimes } 8691541Srgrimes return (0); 8701541Srgrimes} 8711541Srgrimes 8721541Srgrimes/* 8731541Srgrimes * Set up nameidata for a lookup() call and do it 8741541Srgrimes */ 8751549Srgrimesint 8761541Srgrimesnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 8771541Srgrimes register struct nameidata *ndp; 8781541Srgrimes fhandle_t *fhp; 8791541Srgrimes int len; 8801541Srgrimes struct nfssvc_sock *slp; 8811541Srgrimes struct mbuf *nam; 8821541Srgrimes struct mbuf **mdp; 8831541Srgrimes caddr_t *dposp; 8841541Srgrimes struct proc *p; 8851541Srgrimes{ 8861541Srgrimes register int i, rem; 8871541Srgrimes register struct mbuf *md; 8881541Srgrimes register char *fromcp, *tocp; 8891541Srgrimes struct vnode *dp; 8901541Srgrimes int error, rdonly; 8911541Srgrimes struct componentname *cnp = &ndp->ni_cnd; 8921541Srgrimes 8931541Srgrimes MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 8941541Srgrimes /* 8951541Srgrimes * Copy the name from the mbuf list to ndp->ni_pnbuf 8961541Srgrimes * and set the various ndp fields appropriately. 8971541Srgrimes */ 8981541Srgrimes fromcp = *dposp; 8991541Srgrimes tocp = cnp->cn_pnbuf; 9001541Srgrimes md = *mdp; 9011541Srgrimes rem = mtod(md, caddr_t) + md->m_len - fromcp; 9021541Srgrimes cnp->cn_hash = 0; 9031541Srgrimes for (i = 0; i < len; i++) { 9041541Srgrimes while (rem == 0) { 9051541Srgrimes md = md->m_next; 9061541Srgrimes if (md == NULL) { 9071541Srgrimes error = EBADRPC; 9081541Srgrimes goto out; 9091541Srgrimes } 9101541Srgrimes fromcp = mtod(md, caddr_t); 9111541Srgrimes rem = md->m_len; 9121541Srgrimes } 9131541Srgrimes if (*fromcp == '\0' || *fromcp == '/') { 9141541Srgrimes error = EINVAL; 9151541Srgrimes goto out; 9161541Srgrimes } 9171541Srgrimes cnp->cn_hash += (unsigned char)*fromcp; 9181541Srgrimes *tocp++ = *fromcp++; 9191541Srgrimes rem--; 9201541Srgrimes } 9211541Srgrimes *tocp = '\0'; 9221541Srgrimes *mdp = md; 9231541Srgrimes *dposp = fromcp; 9241541Srgrimes len = nfsm_rndup(len)-len; 9251541Srgrimes if (len > 0) { 9261541Srgrimes if (rem >= len) 9271541Srgrimes *dposp += len; 9281541Srgrimes else if (error = nfs_adv(mdp, dposp, len, rem)) 9291541Srgrimes goto out; 9301541Srgrimes } 9311541Srgrimes ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 9321541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 9331541Srgrimes /* 9341541Srgrimes * Extract and set starting directory. 9351541Srgrimes */ 9361541Srgrimes if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 9371541Srgrimes nam, &rdonly)) 9381541Srgrimes goto out; 9391541Srgrimes if (dp->v_type != VDIR) { 9401541Srgrimes vrele(dp); 9411541Srgrimes error = ENOTDIR; 9421541Srgrimes goto out; 9431541Srgrimes } 9441541Srgrimes ndp->ni_startdir = dp; 9451541Srgrimes if (rdonly) 9461541Srgrimes cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 9471541Srgrimes else 9481541Srgrimes cnp->cn_flags |= NOCROSSMOUNT; 9491541Srgrimes /* 9501541Srgrimes * And call lookup() to do the real work 9511541Srgrimes */ 9521541Srgrimes cnp->cn_proc = p; 9531541Srgrimes if (error = lookup(ndp)) 9541541Srgrimes goto out; 9551541Srgrimes /* 9561541Srgrimes * Check for encountering a symbolic link 9571541Srgrimes */ 9581541Srgrimes if (cnp->cn_flags & ISSYMLINK) { 9591541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 9601541Srgrimes vput(ndp->ni_dvp); 9611541Srgrimes else 9621541Srgrimes vrele(ndp->ni_dvp); 9631541Srgrimes vput(ndp->ni_vp); 9641541Srgrimes ndp->ni_vp = NULL; 9651541Srgrimes error = EINVAL; 9661541Srgrimes goto out; 9671541Srgrimes } 9681541Srgrimes /* 9691541Srgrimes * Check for saved name request 9701541Srgrimes */ 9711541Srgrimes if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 9721541Srgrimes cnp->cn_flags |= HASBUF; 9731541Srgrimes return (0); 9741541Srgrimes } 9751541Srgrimesout: 9761541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 9771541Srgrimes return (error); 9781541Srgrimes} 9791541Srgrimes 9801541Srgrimes/* 9811541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 9821541Srgrimes * boundary and only trims off the back end 9831541Srgrimes */ 9841541Srgrimesvoid 9851541Srgrimesnfsm_adj(mp, len, nul) 9861541Srgrimes struct mbuf *mp; 9871541Srgrimes register int len; 9881541Srgrimes int nul; 9891541Srgrimes{ 9901541Srgrimes register struct mbuf *m; 9911541Srgrimes register int count, i; 9921541Srgrimes register char *cp; 9931541Srgrimes 9941541Srgrimes /* 9951541Srgrimes * Trim from tail. Scan the mbuf chain, 9961541Srgrimes * calculating its length and finding the last mbuf. 9971541Srgrimes * If the adjustment only affects this mbuf, then just 9981541Srgrimes * adjust and return. Otherwise, rescan and truncate 9991541Srgrimes * after the remaining size. 10001541Srgrimes */ 10011541Srgrimes count = 0; 10021541Srgrimes m = mp; 10031541Srgrimes for (;;) { 10041541Srgrimes count += m->m_len; 10051541Srgrimes if (m->m_next == (struct mbuf *)0) 10061541Srgrimes break; 10071541Srgrimes m = m->m_next; 10081541Srgrimes } 10091541Srgrimes if (m->m_len > len) { 10101541Srgrimes m->m_len -= len; 10111541Srgrimes if (nul > 0) { 10121541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 10131541Srgrimes for (i = 0; i < nul; i++) 10141541Srgrimes *cp++ = '\0'; 10151541Srgrimes } 10161541Srgrimes return; 10171541Srgrimes } 10181541Srgrimes count -= len; 10191541Srgrimes if (count < 0) 10201541Srgrimes count = 0; 10211541Srgrimes /* 10221541Srgrimes * Correct length for chain is "count". 10231541Srgrimes * Find the mbuf with last data, adjust its length, 10241541Srgrimes * and toss data from remaining mbufs on chain. 10251541Srgrimes */ 10261541Srgrimes for (m = mp; m; m = m->m_next) { 10271541Srgrimes if (m->m_len >= count) { 10281541Srgrimes m->m_len = count; 10291541Srgrimes if (nul > 0) { 10301541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 10311541Srgrimes for (i = 0; i < nul; i++) 10321541Srgrimes *cp++ = '\0'; 10331541Srgrimes } 10341541Srgrimes break; 10351541Srgrimes } 10361541Srgrimes count -= m->m_len; 10371541Srgrimes } 10381541Srgrimes while (m = m->m_next) 10391541Srgrimes m->m_len = 0; 10401541Srgrimes} 10411541Srgrimes 10421541Srgrimes/* 10431541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 10441541Srgrimes * - look up fsid in mount list (if not found ret error) 10451541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 10461541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 10471541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 10481541Srgrimes */ 10491549Srgrimesint 10501541Srgrimesnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 10511541Srgrimes fhandle_t *fhp; 10521541Srgrimes int lockflag; 10531541Srgrimes struct vnode **vpp; 10541541Srgrimes struct ucred *cred; 10551541Srgrimes struct nfssvc_sock *slp; 10561541Srgrimes struct mbuf *nam; 10571541Srgrimes int *rdonlyp; 10581541Srgrimes{ 10591541Srgrimes register struct mount *mp; 10601541Srgrimes register struct nfsuid *uidp; 10611541Srgrimes register int i; 10621541Srgrimes struct ucred *credanon; 10631541Srgrimes int error, exflags; 10641541Srgrimes 10651541Srgrimes *vpp = (struct vnode *)0; 10661541Srgrimes if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 10671541Srgrimes return (ESTALE); 10681541Srgrimes if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon)) 10691541Srgrimes return (error); 10701541Srgrimes /* 10711541Srgrimes * Check/setup credentials. 10721541Srgrimes */ 10731541Srgrimes if (exflags & MNT_EXKERB) { 10741541Srgrimes uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)]; 10751541Srgrimes while (uidp) { 10761541Srgrimes if (uidp->nu_uid == cred->cr_uid) 10771541Srgrimes break; 10781541Srgrimes uidp = uidp->nu_hnext; 10791541Srgrimes } 10801541Srgrimes if (uidp) { 10811541Srgrimes cred->cr_uid = uidp->nu_cr.cr_uid; 10821541Srgrimes for (i = 0; i < uidp->nu_cr.cr_ngroups; i++) 10831541Srgrimes cred->cr_groups[i] = uidp->nu_cr.cr_groups[i]; 10841541Srgrimes } else { 10851541Srgrimes vput(*vpp); 10861541Srgrimes return (NQNFS_AUTHERR); 10871541Srgrimes } 10881541Srgrimes } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 10891541Srgrimes cred->cr_uid = credanon->cr_uid; 10901541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 10911541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 10921541Srgrimes } 10931541Srgrimes if (exflags & MNT_EXRDONLY) 10941541Srgrimes *rdonlyp = 1; 10951541Srgrimes else 10961541Srgrimes *rdonlyp = 0; 10971541Srgrimes if (!lockflag) 10981541Srgrimes VOP_UNLOCK(*vpp); 10991541Srgrimes return (0); 11001541Srgrimes} 11011541Srgrimes 11021541Srgrimes/* 11031541Srgrimes * This function compares two net addresses by family and returns TRUE 11041541Srgrimes * if they are the same host. 11051541Srgrimes * If there is any doubt, return FALSE. 11061541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 11071541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 11081541Srgrimes */ 11091549Srgrimesint 11101541Srgrimesnetaddr_match(family, haddr, nam) 11111541Srgrimes int family; 11121541Srgrimes union nethostaddr *haddr; 11131541Srgrimes struct mbuf *nam; 11141541Srgrimes{ 11151541Srgrimes register struct sockaddr_in *inetaddr; 11161541Srgrimes 11171541Srgrimes switch (family) { 11181541Srgrimes case AF_INET: 11191541Srgrimes inetaddr = mtod(nam, struct sockaddr_in *); 11201541Srgrimes if (inetaddr->sin_family == AF_INET && 11211541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 11221541Srgrimes return (1); 11231541Srgrimes break; 11241541Srgrimes#ifdef ISO 11251541Srgrimes case AF_ISO: 11261541Srgrimes { 11271541Srgrimes register struct sockaddr_iso *isoaddr1, *isoaddr2; 11281541Srgrimes 11291541Srgrimes isoaddr1 = mtod(nam, struct sockaddr_iso *); 11301541Srgrimes isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 11311541Srgrimes if (isoaddr1->siso_family == AF_ISO && 11321541Srgrimes isoaddr1->siso_nlen > 0 && 11331541Srgrimes isoaddr1->siso_nlen == isoaddr2->siso_nlen && 11341541Srgrimes SAME_ISOADDR(isoaddr1, isoaddr2)) 11351541Srgrimes return (1); 11361541Srgrimes break; 11371541Srgrimes } 11381541Srgrimes#endif /* ISO */ 11391541Srgrimes default: 11401541Srgrimes break; 11411541Srgrimes }; 11421541Srgrimes return (0); 11431541Srgrimes} 1144