nfs_srvsubs.c revision 2997
1234370Sjasone/* 2234370Sjasone * Copyright (c) 1989, 1993 3234370Sjasone * The Regents of the University of California. All rights reserved. 4234370Sjasone * 5251300Sjasone * This code is derived from software contributed to Berkeley by 6234370Sjasone * Rick Macklem at The University of Guelph. 7251300Sjasone * 8234370Sjasone * Redistribution and use in source and binary forms, with or without 9234370Sjasone * modification, are permitted provided that the following conditions 10251300Sjasone * are met: 11234370Sjasone * 1. Redistributions of source code must retain the above copyright 12234370Sjasone * notice, this list of conditions and the following disclaimer. 13234370Sjasone * 2. Redistributions in binary form must reproduce the above copyright 14234370Sjasone * notice, this list of conditions and the following disclaimer in the 15234370Sjasone * documentation and/or other materials provided with the distribution. 16234370Sjasone * 3. All advertising materials mentioning features or use of this software 17234370Sjasone * must display the following acknowledgement: 18234370Sjasone * This product includes software developed by the University of 19234370Sjasone * California, Berkeley and its contributors. 20234370Sjasone * 4. Neither the name of the University nor the names of its contributors 21234370Sjasone * may be used to endorse or promote products derived from this software 22234370Sjasone * without specific prior written permission. 23234370Sjasone * 24234370Sjasone * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25234370Sjasone * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26234370Sjasone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27234370Sjasone * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28234370Sjasone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29234370Sjasone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30234370Sjasone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31234370Sjasone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32234370Sjasone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33234370Sjasone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34251300Sjasone * SUCH DAMAGE. 35234370Sjasone * 36234370Sjasone * @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94 37234370Sjasone * $Id: nfs_subs.c,v 1.3 1994/08/02 07:52:13 davidg Exp $ 38234370Sjasone */ 39234370Sjasone 40234370Sjasone/* 41234370Sjasone * These functions support the macros and help fiddle mbuf chains for 42234370Sjasone * the nfs op functions. They do things like create the rpc header and 43234370Sjasone * copy data between mbuf chains and uio lists. 44234370Sjasone */ 45234370Sjasone#include <sys/param.h> 46234370Sjasone#include <sys/proc.h> 47234370Sjasone#include <sys/systm.h> 48234370Sjasone#include <sys/kernel.h> 49234370Sjasone#include <sys/mount.h> 50234370Sjasone#include <sys/vnode.h> 51234370Sjasone#include <sys/namei.h> 52234370Sjasone#include <sys/mbuf.h> 53234370Sjasone#include <sys/socket.h> 54234370Sjasone#include <sys/stat.h> 55234370Sjasone#ifdef VFS_LKM 56234370Sjasone#include <sys/sysent.h> 57234370Sjasone#include <sys/syscall.h> 58234370Sjasone#endif 59234370Sjasone 60234370Sjasone#include <nfs/rpcv2.h> 61234370Sjasone#include <nfs/nfsv2.h> 62234370Sjasone#include <nfs/nfsnode.h> 63234370Sjasone#include <nfs/nfs.h> 64234370Sjasone#include <nfs/xdr_subs.h> 65234370Sjasone#include <nfs/nfsm_subs.h> 66234370Sjasone#include <nfs/nfsmount.h> 67234370Sjasone#include <nfs/nqnfs.h> 68234370Sjasone#include <nfs/nfsrtt.h> 69234370Sjasone 70234370Sjasone#include <miscfs/specfs/specdev.h> 71234370Sjasone 72234370Sjasone#include <netinet/in.h> 73234370Sjasone#ifdef ISO 74234370Sjasone#include <netiso/iso.h> 75234370Sjasone#endif 76234370Sjasone 77234370Sjasone#define TRUE 1 78234370Sjasone#define FALSE 0 79234370Sjasone 80234370Sjasone/* 81234370Sjasone * Data items converted to xdr at startup, since they are constant 82234370Sjasone * This is kinda hokey, but may save a little time doing byte swaps 83234370Sjasone */ 84234370Sjasoneu_long nfs_procids[NFS_NPROCS]; 85234370Sjasoneu_long nfs_xdrneg1; 86234370Sjasoneu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 87234370Sjasone rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred, 88234370Sjasone rpc_auth_kerb; 89234370Sjasoneu_long nfs_vers, nfs_prog, nfs_true, nfs_false; 90234370Sjasone 91234370Sjasone/* And other global data */ 92234370Sjasonestatic u_long nfs_xid = 0; 93234370Sjasoneenum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 94234370Sjasoneextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 95234370Sjasoneextern struct nfsreq nfsreqh; 96234370Sjasoneextern int nqnfs_piggy[NFS_NPROCS]; 97234370Sjasoneextern struct nfsrtt nfsrtt; 98234370Sjasoneextern time_t nqnfsstarttime; 99234370Sjasoneextern u_long nqnfs_prog, nqnfs_vers; 100234370Sjasoneextern int nqsrv_clockskew; 101234370Sjasoneextern int nqsrv_writeslack; 102234370Sjasoneextern int nqsrv_maxlease; 103234370Sjasone 104234370Sjasone#ifdef VFS_LKM 105234370Sjasonestruct getfh_args; 106234370Sjasoneextern int getfh(struct proc *, struct getfh_args *, int *); 107234370Sjasonestruct nfssvc_args; 108234370Sjasoneextern int nfssvc(struct proc *, struct nfssvc_args *, int *); 109234370Sjasone#endif 110234370Sjasone 111234370Sjasone/* 112234370Sjasone * Create the header for an rpc request packet 113234370Sjasone * The hsiz is the size of the rest of the nfs request header. 114234370Sjasone * (just used to decide if a cluster is a good idea) 115234370Sjasone */ 116234370Sjasonestruct mbuf * 117234370Sjasonenfsm_reqh(vp, procid, hsiz, bposp) 118234370Sjasone struct vnode *vp; 119234370Sjasone u_long procid; 120234370Sjasone int hsiz; 121234370Sjasone caddr_t *bposp; 122234370Sjasone{ 123234370Sjasone register struct mbuf *mb; 124234370Sjasone register u_long *tl; 125234370Sjasone register caddr_t bpos; 126234370Sjasone struct mbuf *mb2; 127234370Sjasone struct nfsmount *nmp; 128234370Sjasone int nqflag; 129234370Sjasone 130234370Sjasone MGET(mb, M_WAIT, MT_DATA); 131234370Sjasone if (hsiz >= MINCLSIZE) 132234370Sjasone MCLGET(mb, M_WAIT); 133234370Sjasone mb->m_len = 0; 134234370Sjasone bpos = mtod(mb, caddr_t); 135234370Sjasone 136234370Sjasone /* 137234370Sjasone * For NQNFS, add lease request. 138234370Sjasone */ 139234370Sjasone if (vp) { 140234370Sjasone nmp = VFSTONFS(vp->v_mount); 141234370Sjasone if (nmp->nm_flag & NFSMNT_NQNFS) { 142234370Sjasone nqflag = NQNFS_NEEDLEASE(vp, procid); 143234370Sjasone if (nqflag) { 144234370Sjasone nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 145234370Sjasone *tl++ = txdr_unsigned(nqflag); 146234370Sjasone *tl = txdr_unsigned(nmp->nm_leaseterm); 147234370Sjasone } else { 148234370Sjasone nfsm_build(tl, u_long *, NFSX_UNSIGNED); 149234370Sjasone *tl = 0; 150234370Sjasone } 151234370Sjasone } 152234370Sjasone } 153234370Sjasone /* Finally, return values */ 154234370Sjasone *bposp = bpos; 155234370Sjasone return (mb); 156234370Sjasone} 157234370Sjasone 158234370Sjasone/* 159234370Sjasone * Build the RPC header and fill in the authorization info. 160234370Sjasone * The authorization string argument is only used when the credentials 161234370Sjasone * come from outside of the kernel. 162234370Sjasone * Returns the head of the mbuf list. 163234370Sjasone */ 164234370Sjasonestruct mbuf * 165234370Sjasonenfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, 166234370Sjasone mrest_len, mbp, xidp) 167234370Sjasone register struct ucred *cr; 168234370Sjasone int nqnfs; 169234370Sjasone int procid; 170234370Sjasone int auth_type; 171234370Sjasone int auth_len; 172234370Sjasone char *auth_str; 173234370Sjasone struct mbuf *mrest; 174234370Sjasone int mrest_len; 175234370Sjasone struct mbuf **mbp; 176234370Sjasone u_long *xidp; 177234370Sjasone{ 178234370Sjasone register struct mbuf *mb; 179234370Sjasone register u_long *tl; 180234370Sjasone register caddr_t bpos; 181234370Sjasone register int i; 182234370Sjasone struct mbuf *mreq, *mb2; 183234370Sjasone int siz, grpsiz, authsiz; 184234370Sjasone 185234370Sjasone authsiz = nfsm_rndup(auth_len); 186234370Sjasone if (auth_type == RPCAUTH_NQNFS) 187234370Sjasone authsiz += 2 * NFSX_UNSIGNED; 188234370Sjasone MGETHDR(mb, M_WAIT, MT_DATA); 189234370Sjasone if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) { 190234370Sjasone MCLGET(mb, M_WAIT); 191234370Sjasone } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) { 192234370Sjasone MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED); 193234370Sjasone } else { 194234370Sjasone MH_ALIGN(mb, 8*NFSX_UNSIGNED); 195234370Sjasone } 196234370Sjasone mb->m_len = 0; 197234370Sjasone mreq = mb; 198234370Sjasone bpos = mtod(mb, caddr_t); 199234370Sjasone 200234370Sjasone /* 201234370Sjasone * First the RPC header. 202234370Sjasone */ 203234370Sjasone nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED); 204234370Sjasone if (++nfs_xid == 0) 205234370Sjasone nfs_xid++; 206234370Sjasone *tl++ = *xidp = txdr_unsigned(nfs_xid); 207234370Sjasone *tl++ = rpc_call; 208234370Sjasone *tl++ = rpc_vers; 209234370Sjasone if (nqnfs) { 210234370Sjasone *tl++ = txdr_unsigned(NQNFS_PROG); 211234370Sjasone *tl++ = txdr_unsigned(NQNFS_VER1); 212234370Sjasone } else { 213234370Sjasone *tl++ = txdr_unsigned(NFS_PROG); 214234370Sjasone *tl++ = txdr_unsigned(NFS_VER2); 215234370Sjasone } 216234370Sjasone *tl++ = txdr_unsigned(procid); 217234370Sjasone 218234370Sjasone /* 219234370Sjasone * And then the authorization cred. 220234370Sjasone */ 221234370Sjasone *tl++ = txdr_unsigned(auth_type); 222234370Sjasone *tl = txdr_unsigned(authsiz); 223234370Sjasone switch (auth_type) { 224234370Sjasone case RPCAUTH_UNIX: 225234370Sjasone nfsm_build(tl, u_long *, auth_len); 226234370Sjasone *tl++ = 0; /* stamp ?? */ 227234370Sjasone *tl++ = 0; /* NULL hostname */ 228234370Sjasone *tl++ = txdr_unsigned(cr->cr_uid); 229234370Sjasone *tl++ = txdr_unsigned(cr->cr_groups[0]); 230234370Sjasone grpsiz = (auth_len >> 2) - 5; 231234370Sjasone *tl++ = txdr_unsigned(grpsiz); 232234370Sjasone for (i = 1; i <= grpsiz; i++) 233234370Sjasone *tl++ = txdr_unsigned(cr->cr_groups[i]); 234234370Sjasone break; 235234370Sjasone case RPCAUTH_NQNFS: 236234370Sjasone nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 237234370Sjasone *tl++ = txdr_unsigned(cr->cr_uid); 238234370Sjasone *tl = txdr_unsigned(auth_len); 239234370Sjasone siz = auth_len; 240234370Sjasone while (siz > 0) { 241234370Sjasone if (M_TRAILINGSPACE(mb) == 0) { 242234370Sjasone MGET(mb2, M_WAIT, MT_DATA); 243234370Sjasone if (siz >= MINCLSIZE) 244234370Sjasone MCLGET(mb2, M_WAIT); 245234370Sjasone mb->m_next = mb2; 246234370Sjasone mb = mb2; 247234370Sjasone mb->m_len = 0; 248234370Sjasone bpos = mtod(mb, caddr_t); 249234370Sjasone } 250234370Sjasone i = min(siz, M_TRAILINGSPACE(mb)); 251234370Sjasone bcopy(auth_str, bpos, i); 252234370Sjasone mb->m_len += i; 253234370Sjasone auth_str += i; 254234370Sjasone bpos += i; 255234370Sjasone siz -= i; 256234370Sjasone } 257234370Sjasone if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 258234370Sjasone for (i = 0; i < siz; i++) 259234370Sjasone *bpos++ = '\0'; 260234370Sjasone mb->m_len += siz; 261234370Sjasone } 262234370Sjasone break; 263234370Sjasone }; 264234370Sjasone nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 265234370Sjasone *tl++ = txdr_unsigned(RPCAUTH_NULL); 266234370Sjasone *tl = 0; 267234370Sjasone mb->m_next = mrest; 268234370Sjasone mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len; 269234370Sjasone mreq->m_pkthdr.rcvif = (struct ifnet *)0; 270234370Sjasone *mbp = mb; 271234370Sjasone return (mreq); 272234370Sjasone} 273234370Sjasone 274234370Sjasone/* 275234370Sjasone * copies mbuf chain to the uio scatter/gather list 276234370Sjasone */ 277234370Sjasoneint 278234370Sjasonenfsm_mbuftouio(mrep, uiop, siz, dpos) 279234370Sjasone struct mbuf **mrep; 280234370Sjasone register struct uio *uiop; 281234370Sjasone int siz; 282234370Sjasone caddr_t *dpos; 283234370Sjasone{ 284234370Sjasone register char *mbufcp, *uiocp; 285234370Sjasone register int xfer, left, len; 286234370Sjasone register struct mbuf *mp; 287234370Sjasone long uiosiz, rem; 288234370Sjasone int error = 0; 289234370Sjasone 290234370Sjasone mp = *mrep; 291234370Sjasone mbufcp = *dpos; 292234370Sjasone len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 293234370Sjasone rem = nfsm_rndup(siz)-siz; 294234370Sjasone while (siz > 0) { 295234370Sjasone if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 296234370Sjasone return (EFBIG); 297234370Sjasone left = uiop->uio_iov->iov_len; 298234370Sjasone uiocp = uiop->uio_iov->iov_base; 299234370Sjasone if (left > siz) 300234370Sjasone left = siz; 301234370Sjasone uiosiz = left; 302234370Sjasone while (left > 0) { 303234370Sjasone while (len == 0) { 304234370Sjasone mp = mp->m_next; 305234370Sjasone if (mp == NULL) 306234370Sjasone return (EBADRPC); 307234370Sjasone mbufcp = mtod(mp, caddr_t); 308234370Sjasone len = mp->m_len; 309234370Sjasone } 310234370Sjasone xfer = (left > len) ? len : left; 311234370Sjasone#ifdef notdef 312234370Sjasone /* Not Yet.. */ 313242844Sjasone if (uiop->uio_iov->iov_op != NULL) 314242844Sjasone (*(uiop->uio_iov->iov_op)) 315242844Sjasone (mbufcp, uiocp, xfer); 316242844Sjasone else 317242844Sjasone#endif 318242844Sjasone if (uiop->uio_segflg == UIO_SYSSPACE) 319242844Sjasone bcopy(mbufcp, uiocp, xfer); 320242844Sjasone else 321234370Sjasone copyout(mbufcp, uiocp, xfer); 322234370Sjasone left -= xfer; 323234370Sjasone len -= xfer; 324234370Sjasone mbufcp += xfer; 325234370Sjasone uiocp += xfer; 326234370Sjasone uiop->uio_offset += xfer; 327234370Sjasone uiop->uio_resid -= xfer; 328234370Sjasone } 329234370Sjasone if (uiop->uio_iov->iov_len <= siz) { 330234370Sjasone uiop->uio_iovcnt--; 331234370Sjasone uiop->uio_iov++; 332234370Sjasone } else { 333234370Sjasone uiop->uio_iov->iov_base += uiosiz; 334234370Sjasone uiop->uio_iov->iov_len -= uiosiz; 335234370Sjasone } 336234370Sjasone siz -= uiosiz; 337234370Sjasone } 338234370Sjasone *dpos = mbufcp; 339234370Sjasone *mrep = mp; 340234370Sjasone if (rem > 0) { 341234370Sjasone if (len < rem) 342234370Sjasone error = nfs_adv(mrep, dpos, rem, len); 343234370Sjasone else 344234370Sjasone *dpos += rem; 345234370Sjasone } 346234370Sjasone return (error); 347234370Sjasone} 348234370Sjasone 349234370Sjasone/* 350234370Sjasone * copies a uio scatter/gather list to an mbuf chain... 351234370Sjasone */ 352234370Sjasoneint 353234370Sjasonenfsm_uiotombuf(uiop, mq, siz, bpos) 354234370Sjasone register struct uio *uiop; 355234370Sjasone struct mbuf **mq; 356234370Sjasone int siz; 357234370Sjasone caddr_t *bpos; 358234370Sjasone{ 359234370Sjasone register char *uiocp; 360234370Sjasone register struct mbuf *mp, *mp2; 361234370Sjasone register int xfer, left, mlen; 362234370Sjasone int uiosiz, clflg, rem; 363234370Sjasone char *cp; 364234370Sjasone 365234370Sjasone if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 366234370Sjasone clflg = 1; 367234370Sjasone else 368234370Sjasone clflg = 0; 369234370Sjasone rem = nfsm_rndup(siz)-siz; 370234370Sjasone mp = mp2 = *mq; 371234370Sjasone while (siz > 0) { 372234370Sjasone if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 373234370Sjasone return (EINVAL); 374234370Sjasone left = uiop->uio_iov->iov_len; 375234370Sjasone uiocp = uiop->uio_iov->iov_base; 376234370Sjasone if (left > siz) 377234370Sjasone left = siz; 378234370Sjasone uiosiz = left; 379234370Sjasone while (left > 0) { 380234370Sjasone mlen = M_TRAILINGSPACE(mp); 381234370Sjasone if (mlen == 0) { 382234370Sjasone MGET(mp, M_WAIT, MT_DATA); 383234370Sjasone if (clflg) 384234370Sjasone MCLGET(mp, M_WAIT); 385234370Sjasone mp->m_len = 0; 386234370Sjasone mp2->m_next = mp; 387234370Sjasone mp2 = mp; 388234370Sjasone mlen = M_TRAILINGSPACE(mp); 389234370Sjasone } 390234370Sjasone xfer = (left > mlen) ? mlen : left; 391234370Sjasone#ifdef notdef 392234370Sjasone /* Not Yet.. */ 393234370Sjasone if (uiop->uio_iov->iov_op != NULL) 394234370Sjasone (*(uiop->uio_iov->iov_op)) 395251300Sjasone (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 396251300Sjasone else 397251300Sjasone#endif 398251300Sjasone if (uiop->uio_segflg == UIO_SYSSPACE) 399251300Sjasone bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 400251300Sjasone else 401251300Sjasone copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 402251300Sjasone mp->m_len += xfer; 403251300Sjasone left -= xfer; 404251300Sjasone uiocp += xfer; 405251300Sjasone uiop->uio_offset += xfer; 406251300Sjasone uiop->uio_resid -= xfer; 407251300Sjasone } 408234370Sjasone if (uiop->uio_iov->iov_len <= siz) { 409234370Sjasone uiop->uio_iovcnt--; 410234370Sjasone uiop->uio_iov++; 411234370Sjasone } else { 412234370Sjasone uiop->uio_iov->iov_base += uiosiz; 413234370Sjasone uiop->uio_iov->iov_len -= uiosiz; 414234370Sjasone } 415234370Sjasone siz -= uiosiz; 416234370Sjasone } 417234370Sjasone if (rem > 0) { 418234370Sjasone if (rem > M_TRAILINGSPACE(mp)) { 419234370Sjasone MGET(mp, M_WAIT, MT_DATA); 420234370Sjasone mp->m_len = 0; 421234370Sjasone mp2->m_next = mp; 422234370Sjasone } 423234370Sjasone cp = mtod(mp, caddr_t)+mp->m_len; 424234370Sjasone for (left = 0; left < rem; left++) 425234370Sjasone *cp++ = '\0'; 426234370Sjasone mp->m_len += rem; 427234569Sjasone *bpos = cp; 428234370Sjasone } else 429234569Sjasone *bpos = mtod(mp, caddr_t)+mp->m_len; 430234370Sjasone *mq = mp; 431234370Sjasone return (0); 432234370Sjasone} 433234370Sjasone 434234370Sjasone/* 435234370Sjasone * Help break down an mbuf chain by setting the first siz bytes contiguous 436234370Sjasone * pointed to by returned val. 437234370Sjasone * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 438234370Sjasone * cases. (The macros use the vars. dpos and dpos2) 439234370Sjasone */ 440234370Sjasoneint 441234370Sjasonenfsm_disct(mdp, dposp, siz, left, cp2) 442234370Sjasone struct mbuf **mdp; 443234370Sjasone caddr_t *dposp; 444234370Sjasone int siz; 445234370Sjasone int left; 446234370Sjasone caddr_t *cp2; 447234370Sjasone{ 448234370Sjasone register struct mbuf *mp, *mp2; 449234370Sjasone register int siz2, xfer; 450234370Sjasone register caddr_t p; 451234370Sjasone 452234370Sjasone mp = *mdp; 453234370Sjasone while (left == 0) { 454234370Sjasone *mdp = mp = mp->m_next; 455234370Sjasone if (mp == NULL) 456234370Sjasone return (EBADRPC); 457234370Sjasone left = mp->m_len; 458234370Sjasone *dposp = mtod(mp, caddr_t); 459234370Sjasone } 460234370Sjasone if (left >= siz) { 461234370Sjasone *cp2 = *dposp; 462234370Sjasone *dposp += siz; 463234370Sjasone } else if (mp->m_next == NULL) { 464234370Sjasone return (EBADRPC); 465234370Sjasone } else if (siz > MHLEN) { 466234370Sjasone panic("nfs S too big"); 467234370Sjasone } else { 468234370Sjasone MGET(mp2, M_WAIT, MT_DATA); 469234370Sjasone mp2->m_next = mp->m_next; 470234370Sjasone mp->m_next = mp2; 471234370Sjasone mp->m_len -= left; 472234370Sjasone mp = mp2; 473234370Sjasone *cp2 = p = mtod(mp, caddr_t); 474234370Sjasone bcopy(*dposp, p, left); /* Copy what was left */ 475234370Sjasone siz2 = siz-left; 476234370Sjasone p += left; 477234370Sjasone mp2 = mp->m_next; 478234370Sjasone /* Loop around copying up the siz2 bytes */ 479234370Sjasone while (siz2 > 0) { 480234370Sjasone if (mp2 == NULL) 481234370Sjasone return (EBADRPC); 482234370Sjasone xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 483234370Sjasone if (xfer > 0) { 484234370Sjasone bcopy(mtod(mp2, caddr_t), p, xfer); 485234370Sjasone NFSMADV(mp2, xfer); 486234370Sjasone mp2->m_len -= xfer; 487234370Sjasone p += xfer; 488234370Sjasone siz2 -= xfer; 489234370Sjasone } 490234370Sjasone if (siz2 > 0) 491234370Sjasone mp2 = mp2->m_next; 492234370Sjasone } 493234370Sjasone mp->m_len = siz; 494234370Sjasone *mdp = mp2; 495234370Sjasone *dposp = mtod(mp2, caddr_t); 496234370Sjasone } 497234370Sjasone return (0); 498234370Sjasone} 499234370Sjasone 500234370Sjasone/* 501234370Sjasone * Advance the position in the mbuf chain. 502234370Sjasone */ 503234370Sjasoneint 504234370Sjasonenfs_adv(mdp, dposp, offs, left) 505234370Sjasone struct mbuf **mdp; 506234370Sjasone caddr_t *dposp; 507234370Sjasone int offs; 508234370Sjasone int left; 509234370Sjasone{ 510234370Sjasone register struct mbuf *m; 511234370Sjasone register int s; 512234370Sjasone 513234370Sjasone m = *mdp; 514234370Sjasone s = left; 515234370Sjasone while (s < offs) { 516234370Sjasone offs -= s; 517234370Sjasone m = m->m_next; 518234370Sjasone if (m == NULL) 519234370Sjasone return (EBADRPC); 520234370Sjasone s = m->m_len; 521234370Sjasone } 522234370Sjasone *mdp = m; 523234370Sjasone *dposp = mtod(m, caddr_t)+offs; 524234370Sjasone return (0); 525234370Sjasone} 526234370Sjasone 527234370Sjasone/* 528234370Sjasone * Copy a string into mbufs for the hard cases... 529234370Sjasone */ 530234370Sjasoneint 531234370Sjasonenfsm_strtmbuf(mb, bpos, cp, siz) 532234370Sjasone struct mbuf **mb; 533234370Sjasone char **bpos; 534234370Sjasone char *cp; 535234370Sjasone long siz; 536234370Sjasone{ 537234370Sjasone register struct mbuf *m1 = 0, *m2; 538234370Sjasone long left, xfer, len, tlen; 539234370Sjasone u_long *tl; 540234370Sjasone int putsize; 541234370Sjasone 542234370Sjasone putsize = 1; 543234370Sjasone m2 = *mb; 544234370Sjasone left = M_TRAILINGSPACE(m2); 545234370Sjasone if (left > 0) { 546234370Sjasone tl = ((u_long *)(*bpos)); 547234370Sjasone *tl++ = txdr_unsigned(siz); 548234370Sjasone putsize = 0; 549234370Sjasone left -= NFSX_UNSIGNED; 550234370Sjasone m2->m_len += NFSX_UNSIGNED; 551234370Sjasone if (left > 0) { 552234370Sjasone bcopy(cp, (caddr_t) tl, left); 553234370Sjasone siz -= left; 554234370Sjasone cp += left; 555234370Sjasone m2->m_len += left; 556234370Sjasone left = 0; 557234370Sjasone } 558234370Sjasone } 559234370Sjasone /* Loop around adding mbufs */ 560234370Sjasone while (siz > 0) { 561234370Sjasone MGET(m1, M_WAIT, MT_DATA); 562234370Sjasone if (siz > MLEN) 563234370Sjasone MCLGET(m1, M_WAIT); 564234370Sjasone m1->m_len = NFSMSIZ(m1); 565234370Sjasone m2->m_next = m1; 566234370Sjasone m2 = m1; 567234370Sjasone tl = mtod(m1, u_long *); 568234370Sjasone tlen = 0; 569234370Sjasone if (putsize) { 570234370Sjasone *tl++ = txdr_unsigned(siz); 571234370Sjasone m1->m_len -= NFSX_UNSIGNED; 572234370Sjasone tlen = NFSX_UNSIGNED; 573234370Sjasone putsize = 0; 574234370Sjasone } 575234370Sjasone if (siz < m1->m_len) { 576234370Sjasone len = nfsm_rndup(siz); 577234370Sjasone xfer = siz; 578234370Sjasone if (xfer < len) 579234370Sjasone *(tl+(xfer>>2)) = 0; 580234370Sjasone } else { 581234370Sjasone xfer = len = m1->m_len; 582234370Sjasone } 583234370Sjasone bcopy(cp, (caddr_t) tl, xfer); 584234370Sjasone m1->m_len = len+tlen; 585234370Sjasone siz -= xfer; 586234370Sjasone cp += xfer; 587234370Sjasone } 588234370Sjasone *mb = m1; 589234370Sjasone *bpos = mtod(m1, caddr_t)+m1->m_len; 590235238Sjasone return (0); 591235238Sjasone} 592235238Sjasone 593235238Sjasone/* 594235238Sjasone * Called once to initialize data structures... 595235238Sjasone */ 596234370Sjasoneint 597234370Sjasonenfs_init() 598234370Sjasone{ 599234370Sjasone register int i; 600234370Sjasone 601234370Sjasone nfsrtt.pos = 0; 602234370Sjasone rpc_vers = txdr_unsigned(RPC_VER2); 603234370Sjasone rpc_call = txdr_unsigned(RPC_CALL); 604234370Sjasone rpc_reply = txdr_unsigned(RPC_REPLY); 605234370Sjasone rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 606234370Sjasone rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 607234370Sjasone rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 608234370Sjasone rpc_autherr = txdr_unsigned(RPC_AUTHERR); 609234370Sjasone rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); 610234370Sjasone rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 611234370Sjasone rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); 612234370Sjasone nfs_vers = txdr_unsigned(NFS_VER2); 613234370Sjasone nfs_prog = txdr_unsigned(NFS_PROG); 614234370Sjasone nfs_true = txdr_unsigned(TRUE); 615234370Sjasone nfs_false = txdr_unsigned(FALSE); 616234370Sjasone /* Loop thru nfs procids */ 617234370Sjasone for (i = 0; i < NFS_NPROCS; i++) 618234370Sjasone nfs_procids[i] = txdr_unsigned(i); 619234370Sjasone /* Ensure async daemons disabled */ 620234370Sjasone for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 621234370Sjasone nfs_iodwant[i] = (struct proc *)0; 622234370Sjasone TAILQ_INIT(&nfs_bufq); 623234370Sjasone nfs_xdrneg1 = txdr_unsigned(-1); 624234370Sjasone nfs_nhinit(); /* Init the nfsnode table */ 625234370Sjasone nfsrv_init(0); /* Init server data structures */ 626234370Sjasone nfsrv_initcache(); /* Init the server request cache */ 627234370Sjasone 628234370Sjasone /* 629234370Sjasone * Initialize the nqnfs server stuff. 630234370Sjasone */ 631234370Sjasone if (nqnfsstarttime == 0) { 632234370Sjasone nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 633234370Sjasone + nqsrv_clockskew + nqsrv_writeslack; 634234370Sjasone NQLOADNOVRAM(nqnfsstarttime); 635234370Sjasone nqnfs_prog = txdr_unsigned(NQNFS_PROG); 636234370Sjasone nqnfs_vers = txdr_unsigned(NQNFS_VER1); 637234370Sjasone nqthead.th_head[0] = &nqthead; 638234370Sjasone nqthead.th_head[1] = &nqthead; 639234370Sjasone nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash); 640234370Sjasone } 641234370Sjasone 642234370Sjasone /* 643234370Sjasone * Initialize reply list and start timer 644234370Sjasone */ 645234370Sjasone nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh; 646234370Sjasone nfs_timer(); 647234370Sjasone 648234370Sjasone /* 649234370Sjasone * Set up lease_check and lease_updatetime so that other parts 650234370Sjasone * of the system can call us, if we are loadable. 651234370Sjasone */ 652234370Sjasone lease_check = nfs_lease_check; 653234370Sjasone lease_updatetime = nfs_lease_updatetime; 654234370Sjasone vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */ 655234370Sjasone#ifdef VFS_LKM 656234370Sjasone sysent[SYS_nfssvc].sy_narg = 2; 657234370Sjasone sysent[SYS_nfssvc].sy_call = nfssvc; 658234370Sjasone sysent[SYS_getfh].sy_narg = 2; 659234370Sjasone sysent[SYS_getfh].sy_call = getfh; 660234370Sjasone#endif 661234370Sjasone 662234370Sjasone return (0); 663234370Sjasone} 664234370Sjasone 665234370Sjasone/* 666234370Sjasone * Attribute cache routines. 667245868Sjasone * nfs_loadattrcache() - loads or updates the cache contents from attributes 668234370Sjasone * that are on the mbuf list 669234370Sjasone * nfs_getattrcache() - returns valid attributes if found in cache, returns 670242844Sjasone * error otherwise 671242844Sjasone */ 672242844Sjasone 673242844Sjasone/* 674242844Sjasone * Load the attribute cache (that lives in the nfsnode entry) with 675242844Sjasone * the values on the mbuf list and 676242844Sjasone * Iff vap not NULL 677234370Sjasone * copy the attributes to *vaper 678234370Sjasone */ 679242844Sjasoneint 680234370Sjasonenfs_loadattrcache(vpp, mdp, dposp, vaper) 681234370Sjasone struct vnode **vpp; 682234370Sjasone struct mbuf **mdp; 683234370Sjasone caddr_t *dposp; 684234370Sjasone struct vattr *vaper; 685234370Sjasone{ 686242844Sjasone register struct vnode *vp = *vpp; 687234370Sjasone register struct vattr *vap; 688234370Sjasone register struct nfsv2_fattr *fp; 689234370Sjasone extern int (**spec_nfsv2nodeop_p)(); 690234370Sjasone register struct nfsnode *np, *nq, **nhpp; 691234370Sjasone register long t1; 692234370Sjasone caddr_t dpos, cp2; 693234370Sjasone int error = 0, isnq; 694234370Sjasone struct mbuf *md; 695234370Sjasone enum vtype vtyp; 696234370Sjasone u_short vmode; 697234370Sjasone long rdev; 698234370Sjasone struct timespec mtime; 699234370Sjasone struct vnode *nvp; 700234370Sjasone 701234370Sjasone md = *mdp; 702234370Sjasone dpos = *dposp; 703234370Sjasone t1 = (mtod(md, caddr_t) + md->m_len) - dpos; 704234370Sjasone isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 705234370Sjasone if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2)) 706242844Sjasone return (error); 707242844Sjasone fp = (struct nfsv2_fattr *)cp2; 708234370Sjasone vtyp = nfstov_type(fp->fa_type); 709234370Sjasone vmode = fxdr_unsigned(u_short, fp->fa_mode); 710234370Sjasone if (vtyp == VNON || vtyp == VREG) 711234370Sjasone vtyp = IFTOVT(vmode); 712234370Sjasone if (isnq) { 713234370Sjasone rdev = fxdr_unsigned(long, fp->fa_nqrdev); 714234370Sjasone fxdr_nqtime(&fp->fa_nqmtime, &mtime); 715242844Sjasone } else { 716234370Sjasone rdev = fxdr_unsigned(long, fp->fa_nfsrdev); 717234370Sjasone fxdr_nfstime(&fp->fa_nfsmtime, &mtime); 718234370Sjasone } 719234370Sjasone /* 720234370Sjasone * If v_type == VNON it is a new node, so fill in the v_type, 721234370Sjasone * n_mtime fields. Check to see if it represents a special 722234370Sjasone * device, and if so, check for a possible alias. Once the 723242844Sjasone * correct vnode has been obtained, fill in the rest of the 724234370Sjasone * information. 725234370Sjasone */ 726234370Sjasone np = VTONFS(vp); 727234370Sjasone if (vp->v_type == VNON) { 728234370Sjasone if (vtyp == VCHR && rdev == 0xffffffff) 729234370Sjasone vp->v_type = vtyp = VFIFO; 730234370Sjasone else 731234370Sjasone vp->v_type = vtyp; 732234370Sjasone if (vp->v_type == VFIFO) { 733234370Sjasone extern int (**fifo_nfsv2nodeop_p)(); 734234370Sjasone vp->v_op = fifo_nfsv2nodeop_p; 735234370Sjasone } 736234370Sjasone if (vp->v_type == VCHR || vp->v_type == VBLK) { 737234370Sjasone vp->v_op = spec_nfsv2nodeop_p; 738234370Sjasone if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) { 739234370Sjasone /* 740234370Sjasone * Discard unneeded vnode, but save its nfsnode. 741234370Sjasone */ 742234370Sjasone if (nq = np->n_forw) 743234370Sjasone nq->n_back = np->n_back; 744234370Sjasone *np->n_back = nq; 745242844Sjasone nvp->v_data = vp->v_data; 746234370Sjasone vp->v_data = NULL; 747234370Sjasone vp->v_op = spec_vnodeop_p; 748234370Sjasone vrele(vp); 749234370Sjasone vgone(vp); 750234370Sjasone /* 751234370Sjasone * Reinitialize aliased node. 752234370Sjasone */ 753234370Sjasone np->n_vnode = nvp; 754234370Sjasone nhpp = (struct nfsnode **)nfs_hash(&np->n_fh); 755234370Sjasone if (nq = *nhpp) 756234370Sjasone nq->n_back = &np->n_forw; 757234370Sjasone np->n_forw = nq; 758234370Sjasone np->n_back = nhpp; 759234370Sjasone *nhpp = np; 760234370Sjasone *vpp = vp = nvp; 761234370Sjasone } 762234370Sjasone } 763234370Sjasone np->n_mtime = mtime.ts_sec; 764234370Sjasone } 765234370Sjasone vap = &np->n_vattr; 766234370Sjasone vap->va_type = vtyp; 767234370Sjasone vap->va_mode = (vmode & 07777); 768234370Sjasone vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 769234370Sjasone vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 770234370Sjasone vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 771234370Sjasone vap->va_rdev = (dev_t)rdev; 772242844Sjasone vap->va_mtime = mtime; 773242844Sjasone vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 774234370Sjasone if (isnq) { 775234370Sjasone fxdr_hyper(&fp->fa_nqsize, &vap->va_size); 776234370Sjasone vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize); 777234370Sjasone fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes); 778234370Sjasone vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid); 779234370Sjasone fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime); 780234370Sjasone vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags); 781234370Sjasone fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime); 782234370Sjasone vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen); 783234543Sjasone fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev); 784234370Sjasone } else { 785234370Sjasone vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize); 786234370Sjasone vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize); 787234370Sjasone vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE; 788234370Sjasone vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid); 789234370Sjasone fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime); 790234370Sjasone vap->va_flags = 0; 791234543Sjasone vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_nfsctime.nfs_sec); 792234370Sjasone vap->va_ctime.ts_nsec = 0; 793234543Sjasone vap->va_gen = fxdr_unsigned(u_long, fp->fa_nfsctime.nfs_usec); 794234543Sjasone vap->va_filerev = 0; 795234543Sjasone } 796234370Sjasone if (vap->va_size != np->n_size) { 797234370Sjasone if (vap->va_type == VREG) { 798234543Sjasone if (np->n_flag & NMODIFIED) { 799234370Sjasone if (vap->va_size < np->n_size) 800234370Sjasone vap->va_size = np->n_size; 801234370Sjasone else 802234370Sjasone np->n_size = vap->va_size; 803234370Sjasone } else 804234370Sjasone np->n_size = vap->va_size; 805234370Sjasone vnode_pager_setsize(vp, (u_long)np->n_size); 806234370Sjasone } else 807234370Sjasone np->n_size = vap->va_size; 808234370Sjasone } 809234370Sjasone np->n_attrstamp = time.tv_sec; 810234370Sjasone *dposp = dpos; 811234370Sjasone *mdp = md; 812234370Sjasone if (vaper != NULL) { 813234370Sjasone bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 814234370Sjasone#ifdef notdef 815234370Sjasone if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size) 816234370Sjasone if (np->n_size > vap->va_size) 817234370Sjasone vaper->va_size = np->n_size; 818234543Sjasone#endif 819234370Sjasone if (np->n_flag & NCHG) { 820234370Sjasone if (np->n_flag & NACC) { 821234370Sjasone vaper->va_atime.ts_sec = np->n_atim.tv_sec; 822234370Sjasone vaper->va_atime.ts_nsec = 823234543Sjasone np->n_atim.tv_usec * 1000; 824234370Sjasone } 825234370Sjasone if (np->n_flag & NUPD) { 826234370Sjasone vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 827234370Sjasone vaper->va_mtime.ts_nsec = 828234370Sjasone np->n_mtim.tv_usec * 1000; 829234370Sjasone } 830234370Sjasone } 831234370Sjasone } 832234370Sjasone return (0); 833234370Sjasone} 834234370Sjasone 835234370Sjasone/* 836234370Sjasone * Check the time stamp 837234370Sjasone * If the cache is valid, copy contents to *vap and return 0 838234370Sjasone * otherwise return an error 839234370Sjasone */ 840234370Sjasoneint 841234370Sjasonenfs_getattrcache(vp, vaper) 842234370Sjasone register struct vnode *vp; 843234370Sjasone struct vattr *vaper; 844234370Sjasone{ 845234370Sjasone register struct nfsnode *np = VTONFS(vp); 846234543Sjasone register struct vattr *vap; 847234543Sjasone 848234543Sjasone if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) { 849234543Sjasone if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 850234543Sjasone nfsstats.attrcache_misses++; 851234543Sjasone return (ENOENT); 852234543Sjasone } 853234543Sjasone } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 854234543Sjasone nfsstats.attrcache_misses++; 855234543Sjasone return (ENOENT); 856234543Sjasone } 857234543Sjasone nfsstats.attrcache_hits++; 858234370Sjasone vap = &np->n_vattr; 859234370Sjasone if (vap->va_size != np->n_size) { 860234370Sjasone if (vap->va_type == VREG) { 861234370Sjasone if (np->n_flag & NMODIFIED) { 862234370Sjasone if (vap->va_size < np->n_size) 863234370Sjasone vap->va_size = np->n_size; 864234370Sjasone else 865234370Sjasone np->n_size = vap->va_size; 866234370Sjasone } else 867234370Sjasone np->n_size = vap->va_size; 868234370Sjasone vnode_pager_setsize(vp, (u_long)np->n_size); 869242844Sjasone } else 870234370Sjasone np->n_size = vap->va_size; 871234370Sjasone } 872234370Sjasone bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 873234370Sjasone#ifdef notdef 874234370Sjasone if ((np->n_flag & NMODIFIED) == 0) { 875234370Sjasone np->n_size = vaper->va_size; 876234370Sjasone vnode_pager_setsize(vp, (u_long)np->n_size); 877234370Sjasone } else if (np->n_size > vaper->va_size) 878234370Sjasone if (np->n_size > vaper->va_size) 879234370Sjasone vaper->va_size = np->n_size; 880234370Sjasone#endif 881234370Sjasone if (np->n_flag & NCHG) { 882234370Sjasone if (np->n_flag & NACC) { 883234370Sjasone vaper->va_atime.ts_sec = np->n_atim.tv_sec; 884234370Sjasone vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000; 885234370Sjasone } 886234370Sjasone if (np->n_flag & NUPD) { 887234370Sjasone vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 888234370Sjasone vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000; 889234370Sjasone } 890234370Sjasone } 891234370Sjasone return (0); 892234370Sjasone} 893234370Sjasone 894234370Sjasone/* 895234370Sjasone * Set up nameidata for a lookup() call and do it 896234370Sjasone */ 897234370Sjasoneint 898234370Sjasonenfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 899234370Sjasone register struct nameidata *ndp; 900234370Sjasone fhandle_t *fhp; 901234370Sjasone int len; 902234370Sjasone struct nfssvc_sock *slp; 903234370Sjasone struct mbuf *nam; 904234370Sjasone struct mbuf **mdp; 905234370Sjasone caddr_t *dposp; 906234370Sjasone struct proc *p; 907234370Sjasone{ 908234370Sjasone register int i, rem; 909234370Sjasone register struct mbuf *md; 910234370Sjasone register char *fromcp, *tocp; 911234370Sjasone struct vnode *dp; 912234370Sjasone int error, rdonly; 913242844Sjasone struct componentname *cnp = &ndp->ni_cnd; 914242844Sjasone 915242844Sjasone MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 916242844Sjasone /* 917242844Sjasone * Copy the name from the mbuf list to ndp->ni_pnbuf 918242844Sjasone * and set the various ndp fields appropriately. 919242844Sjasone */ 920242844Sjasone fromcp = *dposp; 921242844Sjasone tocp = cnp->cn_pnbuf; 922242844Sjasone md = *mdp; 923242844Sjasone rem = mtod(md, caddr_t) + md->m_len - fromcp; 924242844Sjasone cnp->cn_hash = 0; 925242844Sjasone for (i = 0; i < len; i++) { 926242844Sjasone while (rem == 0) { 927234370Sjasone md = md->m_next; 928234370Sjasone if (md == NULL) { 929242844Sjasone error = EBADRPC; 930234370Sjasone goto out; 931234370Sjasone } 932234370Sjasone fromcp = mtod(md, caddr_t); 933234370Sjasone rem = md->m_len; 934234370Sjasone } 935234370Sjasone if (*fromcp == '\0' || *fromcp == '/') { 936234370Sjasone error = EINVAL; 937234370Sjasone goto out; 938234370Sjasone } 939234370Sjasone cnp->cn_hash += (unsigned char)*fromcp; 940234370Sjasone *tocp++ = *fromcp++; 941234370Sjasone rem--; 942234370Sjasone } 943234370Sjasone *tocp = '\0'; 944234370Sjasone *mdp = md; 945234370Sjasone *dposp = fromcp; 946234370Sjasone len = nfsm_rndup(len)-len; 947234370Sjasone if (len > 0) { 948234370Sjasone if (rem >= len) 949234370Sjasone *dposp += len; 950234370Sjasone else if (error = nfs_adv(mdp, dposp, len, rem)) 951234370Sjasone goto out; 952234370Sjasone } 953234370Sjasone ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 954234370Sjasone cnp->cn_nameptr = cnp->cn_pnbuf; 955234370Sjasone /* 956234370Sjasone * Extract and set starting directory. 957234370Sjasone */ 958234370Sjasone if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 959234370Sjasone nam, &rdonly)) 960234370Sjasone goto out; 961234370Sjasone if (dp->v_type != VDIR) { 962234370Sjasone vrele(dp); 963234370Sjasone error = ENOTDIR; 964234370Sjasone goto out; 965234370Sjasone } 966234370Sjasone ndp->ni_startdir = dp; 967234370Sjasone if (rdonly) 968234370Sjasone cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 969234370Sjasone else 970234370Sjasone cnp->cn_flags |= NOCROSSMOUNT; 971234370Sjasone /* 972234370Sjasone * And call lookup() to do the real work 973234370Sjasone */ 974234370Sjasone cnp->cn_proc = p; 975234370Sjasone if (error = lookup(ndp)) 976234370Sjasone goto out; 977234370Sjasone /* 978234370Sjasone * Check for encountering a symbolic link 979234370Sjasone */ 980234370Sjasone if (cnp->cn_flags & ISSYMLINK) { 981234370Sjasone if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 982234370Sjasone vput(ndp->ni_dvp); 983234370Sjasone else 984234370Sjasone vrele(ndp->ni_dvp); 985234370Sjasone vput(ndp->ni_vp); 986234370Sjasone ndp->ni_vp = NULL; 987234370Sjasone error = EINVAL; 988234370Sjasone goto out; 989234370Sjasone } 990234370Sjasone /* 991234370Sjasone * Check for saved name request 992234370Sjasone */ 993234370Sjasone if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 994242844Sjasone cnp->cn_flags |= HASBUF; 995242844Sjasone return (0); 996242844Sjasone } 997242844Sjasoneout: 998242844Sjasone FREE(cnp->cn_pnbuf, M_NAMEI); 999234370Sjasone return (error); 1000234370Sjasone} 1001234370Sjasone 1002234370Sjasone/* 1003234370Sjasone * A fiddled version of m_adj() that ensures null fill to a long 1004234370Sjasone * boundary and only trims off the back end 1005234370Sjasone */ 1006234370Sjasonevoid 1007234370Sjasonenfsm_adj(mp, len, nul) 1008234370Sjasone struct mbuf *mp; 1009234370Sjasone register int len; 1010234370Sjasone int nul; 1011234370Sjasone{ 1012234370Sjasone register struct mbuf *m; 1013234370Sjasone register int count, i; 1014234370Sjasone register char *cp; 1015234370Sjasone 1016234370Sjasone /* 1017234370Sjasone * Trim from tail. Scan the mbuf chain, 1018234370Sjasone * calculating its length and finding the last mbuf. 1019234370Sjasone * If the adjustment only affects this mbuf, then just 1020234370Sjasone * adjust and return. Otherwise, rescan and truncate 1021234370Sjasone * after the remaining size. 1022234370Sjasone */ 1023234370Sjasone count = 0; 1024234370Sjasone m = mp; 1025234370Sjasone for (;;) { 1026234370Sjasone count += m->m_len; 1027234370Sjasone if (m->m_next == (struct mbuf *)0) 1028234370Sjasone break; 1029234370Sjasone m = m->m_next; 1030234370Sjasone } 1031234370Sjasone if (m->m_len > len) { 1032234370Sjasone m->m_len -= len; 1033234370Sjasone if (nul > 0) { 1034234370Sjasone cp = mtod(m, caddr_t)+m->m_len-nul; 1035234370Sjasone for (i = 0; i < nul; i++) 1036234370Sjasone *cp++ = '\0'; 1037234370Sjasone } 1038242844Sjasone return; 1039242844Sjasone } 1040242844Sjasone count -= len; 1041234370Sjasone if (count < 0) 1042234370Sjasone count = 0; 1043234370Sjasone /* 1044234370Sjasone * Correct length for chain is "count". 1045234370Sjasone * Find the mbuf with last data, adjust its length, 1046235322Sjasone * and toss data from remaining mbufs on chain. 1047234370Sjasone */ 1048234370Sjasone for (m = mp; m; m = m->m_next) { 1049234370Sjasone if (m->m_len >= count) { 1050234370Sjasone m->m_len = count; 1051235322Sjasone if (nul > 0) { 1052234370Sjasone cp = mtod(m, caddr_t)+m->m_len-nul; 1053234370Sjasone for (i = 0; i < nul; i++) 1054234370Sjasone *cp++ = '\0'; 1055234370Sjasone } 1056234370Sjasone break; 1057234370Sjasone } 1058234370Sjasone count -= m->m_len; 1059234370Sjasone } 1060234370Sjasone while (m = m->m_next) 1061234370Sjasone m->m_len = 0; 1062234370Sjasone} 1063234370Sjasone 1064234370Sjasone/* 1065234370Sjasone * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1066234370Sjasone * - look up fsid in mount list (if not found ret error) 1067234370Sjasone * - get vp and export rights by calling VFS_FHTOVP() 1068234370Sjasone * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1069234370Sjasone * - if not lockflag unlock it with VOP_UNLOCK() 1070234370Sjasone */ 1071234370Sjasoneint 1072234370Sjasonenfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 1073234370Sjasone fhandle_t *fhp; 1074234370Sjasone int lockflag; 1075234370Sjasone struct vnode **vpp; 1076234370Sjasone struct ucred *cred; 1077234370Sjasone struct nfssvc_sock *slp; 1078234370Sjasone struct mbuf *nam; 1079242844Sjasone int *rdonlyp; 1080242844Sjasone{ 1081242844Sjasone register struct mount *mp; 1082242844Sjasone register struct nfsuid *uidp; 1083242844Sjasone register int i; 1084242844Sjasone struct ucred *credanon; 1085242844Sjasone int error, exflags; 1086242844Sjasone 1087242844Sjasone *vpp = (struct vnode *)0; 1088234370Sjasone if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 1089234370Sjasone return (ESTALE); 1090234370Sjasone if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon)) 1091234370Sjasone return (error); 1092234370Sjasone /* 1093234370Sjasone * Check/setup credentials. 1094234370Sjasone */ 1095234370Sjasone if (exflags & MNT_EXKERB) { 1096234370Sjasone uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)]; 1097234370Sjasone while (uidp) { 1098234370Sjasone if (uidp->nu_uid == cred->cr_uid) 1099234370Sjasone break; 1100234370Sjasone uidp = uidp->nu_hnext; 1101234370Sjasone } 1102234370Sjasone if (uidp) { 1103234370Sjasone cred->cr_uid = uidp->nu_cr.cr_uid; 1104234370Sjasone for (i = 0; i < uidp->nu_cr.cr_ngroups; i++) 1105234370Sjasone cred->cr_groups[i] = uidp->nu_cr.cr_groups[i]; 1106234370Sjasone } else { 1107234370Sjasone vput(*vpp); 1108234370Sjasone return (NQNFS_AUTHERR); 1109234370Sjasone } 1110234370Sjasone } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1111234370Sjasone cred->cr_uid = credanon->cr_uid; 1112234370Sjasone for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1113234370Sjasone cred->cr_groups[i] = credanon->cr_groups[i]; 1114234370Sjasone } 1115234370Sjasone if (exflags & MNT_EXRDONLY) 1116234370Sjasone *rdonlyp = 1; 1117234370Sjasone else 1118234370Sjasone *rdonlyp = 0; 1119234370Sjasone if (!lockflag) 1120234370Sjasone VOP_UNLOCK(*vpp); 1121234370Sjasone return (0); 1122234370Sjasone} 1123234370Sjasone 1124234370Sjasone/* 1125234370Sjasone * This function compares two net addresses by family and returns TRUE 1126234370Sjasone * if they are the same host. 1127234370Sjasone * If there is any doubt, return FALSE. 1128234370Sjasone * The AF_INET family is handled as a special case so that address mbufs 1129234370Sjasone * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1130234370Sjasone */ 1131234370Sjasoneint 1132234370Sjasonenetaddr_match(family, haddr, nam) 1133234370Sjasone int family; 1134234370Sjasone union nethostaddr *haddr; 1135234370Sjasone struct mbuf *nam; 1136234370Sjasone{ 1137234370Sjasone register struct sockaddr_in *inetaddr; 1138234370Sjasone 1139234370Sjasone switch (family) { 1140234370Sjasone case AF_INET: 1141234370Sjasone inetaddr = mtod(nam, struct sockaddr_in *); 1142234370Sjasone if (inetaddr->sin_family == AF_INET && 1143234370Sjasone inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 1144234370Sjasone return (1); 1145234370Sjasone break; 1146234370Sjasone#ifdef ISO 1147234370Sjasone case AF_ISO: 1148234370Sjasone { 1149234370Sjasone register struct sockaddr_iso *isoaddr1, *isoaddr2; 1150234370Sjasone 1151234370Sjasone isoaddr1 = mtod(nam, struct sockaddr_iso *); 1152234370Sjasone isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 1153234370Sjasone if (isoaddr1->siso_family == AF_ISO && 1154234370Sjasone isoaddr1->siso_nlen > 0 && 1155234370Sjasone isoaddr1->siso_nlen == isoaddr2->siso_nlen && 1156234370Sjasone SAME_ISOADDR(isoaddr1, isoaddr2)) 1157234370Sjasone return (1); 1158234370Sjasone break; 1159234370Sjasone } 1160234370Sjasone#endif /* ISO */ 1161234370Sjasone default: 1162234370Sjasone break; 1163234370Sjasone }; 1164234370Sjasone return (0); 1165234370Sjasone} 1166234370Sjasone