Home | History | Annotate | Line # | Download | only in nfs
nfs_subs.c revision 1.15
      1 /*	$NetBSD: nfs_subs.c,v 1.15 1994/07/22 23:16:36 mycroft Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1989, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * Rick Macklem at The University of Guelph.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *	This product includes software developed by the University of
     21  *	California, Berkeley and its contributors.
     22  * 4. Neither the name of the University nor the names of its contributors
     23  *    may be used to endorse or promote products derived from this software
     24  *    without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     36  * SUCH DAMAGE.
     37  *
     38  *	@(#)nfs_subs.c	8.3 (Berkeley) 1/4/94
     39  */
     40 
     41 /*
     42  * These functions support the macros and help fiddle mbuf chains for
     43  * the nfs op functions. They do things like create the rpc header and
     44  * copy data between mbuf chains and uio lists.
     45  */
     46 #include <sys/param.h>
     47 #include <sys/proc.h>
     48 #include <sys/systm.h>
     49 #include <sys/kernel.h>
     50 #include <sys/mount.h>
     51 #include <sys/vnode.h>
     52 #include <sys/namei.h>
     53 #include <sys/mbuf.h>
     54 #include <sys/socket.h>
     55 #include <sys/stat.h>
     56 
     57 #include <nfs/rpcv2.h>
     58 #include <nfs/nfsv2.h>
     59 #include <nfs/nfsnode.h>
     60 #include <nfs/nfs.h>
     61 #include <nfs/xdr_subs.h>
     62 #include <nfs/nfsm_subs.h>
     63 #include <nfs/nfsmount.h>
     64 #include <nfs/nqnfs.h>
     65 #include <nfs/nfsrtt.h>
     66 
     67 #include <miscfs/specfs/specdev.h>
     68 
     69 #include <netinet/in.h>
     70 #ifdef ISO
     71 #include <netiso/iso.h>
     72 #endif
     73 
     74 #define TRUE	1
     75 #define	FALSE	0
     76 
     77 /*
     78  * Data items converted to xdr at startup, since they are constant
     79  * This is kinda hokey, but may save a little time doing byte swaps
     80  */
     81 u_long nfs_procids[NFS_NPROCS];
     82 u_long nfs_xdrneg1;
     83 u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
     84 	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
     85 	rpc_auth_kerb;
     86 u_long nfs_vers, nfs_prog, nfs_true, nfs_false;
     87 
     88 /* And other global data */
     89 static u_long nfs_xid = 0;
     90 enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
     91 extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
     92 extern struct nfsreq nfsreqh;
     93 extern int nqnfs_piggy[NFS_NPROCS];
     94 extern struct nfsrtt nfsrtt;
     95 extern time_t nqnfsstarttime;
     96 extern u_long nqnfs_prog, nqnfs_vers;
     97 extern int nqsrv_clockskew;
     98 extern int nqsrv_writeslack;
     99 extern int nqsrv_maxlease;
    100 
    101 /*
    102  * Create the header for an rpc request packet
    103  * The hsiz is the size of the rest of the nfs request header.
    104  * (just used to decide if a cluster is a good idea)
    105  */
    106 struct mbuf *
    107 nfsm_reqh(vp, procid, hsiz, bposp)
    108 	struct vnode *vp;
    109 	u_long procid;
    110 	int hsiz;
    111 	caddr_t *bposp;
    112 {
    113 	register struct mbuf *mb;
    114 	register u_long *tl;
    115 	register caddr_t bpos;
    116 	struct mbuf *mb2;
    117 	struct nfsmount *nmp;
    118 	int nqflag;
    119 
    120 	MGET(mb, M_WAIT, MT_DATA);
    121 	if (hsiz >= MINCLSIZE)
    122 		MCLGET(mb, M_WAIT);
    123 	mb->m_len = 0;
    124 	bpos = mtod(mb, caddr_t);
    125 
    126 	/*
    127 	 * For NQNFS, add lease request.
    128 	 */
    129 	if (vp) {
    130 		nmp = VFSTONFS(vp->v_mount);
    131 		if (nmp->nm_flag & NFSMNT_NQNFS) {
    132 			nqflag = NQNFS_NEEDLEASE(vp, procid);
    133 			if (nqflag) {
    134 				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
    135 				*tl++ = txdr_unsigned(nqflag);
    136 				*tl = txdr_unsigned(nmp->nm_leaseterm);
    137 			} else {
    138 				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
    139 				*tl = 0;
    140 			}
    141 		}
    142 	}
    143 	/* Finally, return values */
    144 	*bposp = bpos;
    145 	return (mb);
    146 }
    147 
    148 /*
    149  * Build the RPC header and fill in the authorization info.
    150  * The authorization string argument is only used when the credentials
    151  * come from outside of the kernel.
    152  * Returns the head of the mbuf list.
    153  */
    154 struct mbuf *
    155 nfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
    156 	mrest_len, mbp, xidp)
    157 	register struct ucred *cr;
    158 	int nqnfs;
    159 	int procid;
    160 	int auth_type;
    161 	int auth_len;
    162 	char *auth_str;
    163 	struct mbuf *mrest;
    164 	int mrest_len;
    165 	struct mbuf **mbp;
    166 	u_long *xidp;
    167 {
    168 	register struct mbuf *mb;
    169 	register u_long *tl;
    170 	register caddr_t bpos;
    171 	register int i;
    172 	struct mbuf *mreq, *mb2;
    173 	int siz, grpsiz, authsiz;
    174 
    175 	authsiz = nfsm_rndup(auth_len);
    176 	if (auth_type == RPCAUTH_NQNFS)
    177 		authsiz += 2 * NFSX_UNSIGNED;
    178 	MGETHDR(mb, M_WAIT, MT_DATA);
    179 	if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
    180 		MCLGET(mb, M_WAIT);
    181 	} else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
    182 		MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
    183 	} else {
    184 		MH_ALIGN(mb, 8*NFSX_UNSIGNED);
    185 	}
    186 	mb->m_len = 0;
    187 	mreq = mb;
    188 	bpos = mtod(mb, caddr_t);
    189 
    190 	/*
    191 	 * First the RPC header.
    192 	 */
    193 	nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
    194 	if (++nfs_xid == 0)
    195 		nfs_xid++;
    196 	*tl++ = *xidp = txdr_unsigned(nfs_xid);
    197 	*tl++ = rpc_call;
    198 	*tl++ = rpc_vers;
    199 	if (nqnfs) {
    200 		*tl++ = txdr_unsigned(NQNFS_PROG);
    201 		*tl++ = txdr_unsigned(NQNFS_VER1);
    202 	} else {
    203 		*tl++ = txdr_unsigned(NFS_PROG);
    204 		*tl++ = txdr_unsigned(NFS_VER2);
    205 	}
    206 	*tl++ = txdr_unsigned(procid);
    207 
    208 	/*
    209 	 * And then the authorization cred.
    210 	 */
    211 	*tl++ = txdr_unsigned(auth_type);
    212 	*tl = txdr_unsigned(authsiz);
    213 	switch (auth_type) {
    214 	case RPCAUTH_UNIX:
    215 		nfsm_build(tl, u_long *, auth_len);
    216 		*tl++ = 0;		/* stamp ?? */
    217 		*tl++ = 0;		/* NULL hostname */
    218 		*tl++ = txdr_unsigned(cr->cr_uid);
    219 		*tl++ = txdr_unsigned(cr->cr_groups[0]);
    220 		grpsiz = (auth_len >> 2) - 5;
    221 		*tl++ = txdr_unsigned(grpsiz);
    222 		for (i = 1; i <= grpsiz; i++)
    223 			*tl++ = txdr_unsigned(cr->cr_groups[i]);
    224 		break;
    225 	case RPCAUTH_NQNFS:
    226 		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
    227 		*tl++ = txdr_unsigned(cr->cr_uid);
    228 		*tl = txdr_unsigned(auth_len);
    229 		siz = auth_len;
    230 		while (siz > 0) {
    231 			if (M_TRAILINGSPACE(mb) == 0) {
    232 				MGET(mb2, M_WAIT, MT_DATA);
    233 				if (siz >= MINCLSIZE)
    234 					MCLGET(mb2, M_WAIT);
    235 				mb->m_next = mb2;
    236 				mb = mb2;
    237 				mb->m_len = 0;
    238 				bpos = mtod(mb, caddr_t);
    239 			}
    240 			i = min(siz, M_TRAILINGSPACE(mb));
    241 			bcopy(auth_str, bpos, i);
    242 			mb->m_len += i;
    243 			auth_str += i;
    244 			bpos += i;
    245 			siz -= i;
    246 		}
    247 		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
    248 			for (i = 0; i < siz; i++)
    249 				*bpos++ = '\0';
    250 			mb->m_len += siz;
    251 		}
    252 		break;
    253 	};
    254 	nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
    255 	*tl++ = txdr_unsigned(RPCAUTH_NULL);
    256 	*tl = 0;
    257 	mb->m_next = mrest;
    258 	mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
    259 	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
    260 	*mbp = mb;
    261 	return (mreq);
    262 }
    263 
    264 /*
    265  * copies mbuf chain to the uio scatter/gather list
    266  */
    267 nfsm_mbuftouio(mrep, uiop, siz, dpos)
    268 	struct mbuf **mrep;
    269 	register struct uio *uiop;
    270 	int siz;
    271 	caddr_t *dpos;
    272 {
    273 	register char *mbufcp, *uiocp;
    274 	register int xfer, left, len;
    275 	register struct mbuf *mp;
    276 	long uiosiz, rem;
    277 	int error = 0;
    278 
    279 	mp = *mrep;
    280 	mbufcp = *dpos;
    281 	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
    282 	rem = nfsm_rndup(siz)-siz;
    283 	while (siz > 0) {
    284 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
    285 			return (EFBIG);
    286 		left = uiop->uio_iov->iov_len;
    287 		uiocp = uiop->uio_iov->iov_base;
    288 		if (left > siz)
    289 			left = siz;
    290 		uiosiz = left;
    291 		while (left > 0) {
    292 			while (len == 0) {
    293 				mp = mp->m_next;
    294 				if (mp == NULL)
    295 					return (EBADRPC);
    296 				mbufcp = mtod(mp, caddr_t);
    297 				len = mp->m_len;
    298 			}
    299 			xfer = (left > len) ? len : left;
    300 #ifdef notdef
    301 			/* Not Yet.. */
    302 			if (uiop->uio_iov->iov_op != NULL)
    303 				(*(uiop->uio_iov->iov_op))
    304 				(mbufcp, uiocp, xfer);
    305 			else
    306 #endif
    307 			if (uiop->uio_segflg == UIO_SYSSPACE)
    308 				bcopy(mbufcp, uiocp, xfer);
    309 			else
    310 				copyout(mbufcp, uiocp, xfer);
    311 			left -= xfer;
    312 			len -= xfer;
    313 			mbufcp += xfer;
    314 			uiocp += xfer;
    315 			uiop->uio_offset += xfer;
    316 			uiop->uio_resid -= xfer;
    317 		}
    318 		if (uiop->uio_iov->iov_len <= siz) {
    319 			uiop->uio_iovcnt--;
    320 			uiop->uio_iov++;
    321 		} else {
    322 			uiop->uio_iov->iov_base += uiosiz;
    323 			uiop->uio_iov->iov_len -= uiosiz;
    324 		}
    325 		siz -= uiosiz;
    326 	}
    327 	*dpos = mbufcp;
    328 	*mrep = mp;
    329 	if (rem > 0) {
    330 		if (len < rem)
    331 			error = nfs_adv(mrep, dpos, rem, len);
    332 		else
    333 			*dpos += rem;
    334 	}
    335 	return (error);
    336 }
    337 
    338 /*
    339  * copies a uio scatter/gather list to an mbuf chain...
    340  */
    341 nfsm_uiotombuf(uiop, mq, siz, bpos)
    342 	register struct uio *uiop;
    343 	struct mbuf **mq;
    344 	int siz;
    345 	caddr_t *bpos;
    346 {
    347 	register char *uiocp;
    348 	register struct mbuf *mp, *mp2;
    349 	register int xfer, left, mlen;
    350 	int uiosiz, clflg, rem;
    351 	char *cp;
    352 
    353 	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
    354 		clflg = 1;
    355 	else
    356 		clflg = 0;
    357 	rem = nfsm_rndup(siz)-siz;
    358 	mp = mp2 = *mq;
    359 	while (siz > 0) {
    360 		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
    361 			return (EINVAL);
    362 		left = uiop->uio_iov->iov_len;
    363 		uiocp = uiop->uio_iov->iov_base;
    364 		if (left > siz)
    365 			left = siz;
    366 		uiosiz = left;
    367 		while (left > 0) {
    368 			mlen = M_TRAILINGSPACE(mp);
    369 			if (mlen == 0) {
    370 				MGET(mp, M_WAIT, MT_DATA);
    371 				if (clflg)
    372 					MCLGET(mp, M_WAIT);
    373 				mp->m_len = 0;
    374 				mp2->m_next = mp;
    375 				mp2 = mp;
    376 				mlen = M_TRAILINGSPACE(mp);
    377 			}
    378 			xfer = (left > mlen) ? mlen : left;
    379 #ifdef notdef
    380 			/* Not Yet.. */
    381 			if (uiop->uio_iov->iov_op != NULL)
    382 				(*(uiop->uio_iov->iov_op))
    383 				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
    384 			else
    385 #endif
    386 			if (uiop->uio_segflg == UIO_SYSSPACE)
    387 				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
    388 			else
    389 				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
    390 			mp->m_len += xfer;
    391 			left -= xfer;
    392 			uiocp += xfer;
    393 			uiop->uio_offset += xfer;
    394 			uiop->uio_resid -= xfer;
    395 		}
    396 		if (uiop->uio_iov->iov_len <= siz) {
    397 			uiop->uio_iovcnt--;
    398 			uiop->uio_iov++;
    399 		} else {
    400 			uiop->uio_iov->iov_base += uiosiz;
    401 			uiop->uio_iov->iov_len -= uiosiz;
    402 		}
    403 		siz -= uiosiz;
    404 	}
    405 	if (rem > 0) {
    406 		if (rem > M_TRAILINGSPACE(mp)) {
    407 			MGET(mp, M_WAIT, MT_DATA);
    408 			mp->m_len = 0;
    409 			mp2->m_next = mp;
    410 		}
    411 		cp = mtod(mp, caddr_t)+mp->m_len;
    412 		for (left = 0; left < rem; left++)
    413 			*cp++ = '\0';
    414 		mp->m_len += rem;
    415 		*bpos = cp;
    416 	} else
    417 		*bpos = mtod(mp, caddr_t)+mp->m_len;
    418 	*mq = mp;
    419 	return (0);
    420 }
    421 
    422 /*
    423  * Help break down an mbuf chain by setting the first siz bytes contiguous
    424  * pointed to by returned val.
    425  * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
    426  * cases. (The macros use the vars. dpos and dpos2)
    427  */
    428 nfsm_disct(mdp, dposp, siz, left, cp2)
    429 	struct mbuf **mdp;
    430 	caddr_t *dposp;
    431 	int siz;
    432 	int left;
    433 	caddr_t *cp2;
    434 {
    435 	register struct mbuf *mp, *mp2;
    436 	register int siz2, xfer;
    437 	register caddr_t p;
    438 
    439 	mp = *mdp;
    440 	while (left == 0) {
    441 		*mdp = mp = mp->m_next;
    442 		if (mp == NULL)
    443 			return (EBADRPC);
    444 		left = mp->m_len;
    445 		*dposp = mtod(mp, caddr_t);
    446 	}
    447 	if (left >= siz) {
    448 		*cp2 = *dposp;
    449 		*dposp += siz;
    450 	} else if (mp->m_next == NULL) {
    451 		return (EBADRPC);
    452 	} else if (siz > MHLEN) {
    453 		panic("nfs S too big");
    454 	} else {
    455 		MGET(mp2, M_WAIT, MT_DATA);
    456 		mp2->m_next = mp->m_next;
    457 		mp->m_next = mp2;
    458 		mp->m_len -= left;
    459 		mp = mp2;
    460 		*cp2 = p = mtod(mp, caddr_t);
    461 		bcopy(*dposp, p, left);		/* Copy what was left */
    462 		siz2 = siz-left;
    463 		p += left;
    464 		mp2 = mp->m_next;
    465 		/* Loop around copying up the siz2 bytes */
    466 		while (siz2 > 0) {
    467 			if (mp2 == NULL)
    468 				return (EBADRPC);
    469 			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
    470 			if (xfer > 0) {
    471 				bcopy(mtod(mp2, caddr_t), p, xfer);
    472 				NFSMADV(mp2, xfer);
    473 				mp2->m_len -= xfer;
    474 				p += xfer;
    475 				siz2 -= xfer;
    476 			}
    477 			if (siz2 > 0)
    478 				mp2 = mp2->m_next;
    479 		}
    480 		mp->m_len = siz;
    481 		*mdp = mp2;
    482 		*dposp = mtod(mp2, caddr_t);
    483 	}
    484 	return (0);
    485 }
    486 
    487 /*
    488  * Advance the position in the mbuf chain.
    489  */
    490 nfs_adv(mdp, dposp, offs, left)
    491 	struct mbuf **mdp;
    492 	caddr_t *dposp;
    493 	int offs;
    494 	int left;
    495 {
    496 	register struct mbuf *m;
    497 	register int s;
    498 
    499 	m = *mdp;
    500 	s = left;
    501 	while (s < offs) {
    502 		offs -= s;
    503 		m = m->m_next;
    504 		if (m == NULL)
    505 			return (EBADRPC);
    506 		s = m->m_len;
    507 	}
    508 	*mdp = m;
    509 	*dposp = mtod(m, caddr_t)+offs;
    510 	return (0);
    511 }
    512 
    513 /*
    514  * Copy a string into mbufs for the hard cases...
    515  */
    516 nfsm_strtmbuf(mb, bpos, cp, siz)
    517 	struct mbuf **mb;
    518 	char **bpos;
    519 	char *cp;
    520 	long siz;
    521 {
    522 	register struct mbuf *m1, *m2;
    523 	long left, xfer, len, tlen;
    524 	u_long *tl;
    525 	int putsize;
    526 
    527 	putsize = 1;
    528 	m2 = *mb;
    529 	left = M_TRAILINGSPACE(m2);
    530 	if (left > 0) {
    531 		tl = ((u_long *)(*bpos));
    532 		*tl++ = txdr_unsigned(siz);
    533 		putsize = 0;
    534 		left -= NFSX_UNSIGNED;
    535 		m2->m_len += NFSX_UNSIGNED;
    536 		if (left > 0) {
    537 			bcopy(cp, (caddr_t) tl, left);
    538 			siz -= left;
    539 			cp += left;
    540 			m2->m_len += left;
    541 			left = 0;
    542 		}
    543 	}
    544 	/* Loop around adding mbufs */
    545 	while (siz > 0) {
    546 		MGET(m1, M_WAIT, MT_DATA);
    547 		if (siz > MLEN)
    548 			MCLGET(m1, M_WAIT);
    549 		m1->m_len = NFSMSIZ(m1);
    550 		m2->m_next = m1;
    551 		m2 = m1;
    552 		tl = mtod(m1, u_long *);
    553 		tlen = 0;
    554 		if (putsize) {
    555 			*tl++ = txdr_unsigned(siz);
    556 			m1->m_len -= NFSX_UNSIGNED;
    557 			tlen = NFSX_UNSIGNED;
    558 			putsize = 0;
    559 		}
    560 		if (siz < m1->m_len) {
    561 			len = nfsm_rndup(siz);
    562 			xfer = siz;
    563 			if (xfer < len)
    564 				*(tl+(xfer>>2)) = 0;
    565 		} else {
    566 			xfer = len = m1->m_len;
    567 		}
    568 		bcopy(cp, (caddr_t) tl, xfer);
    569 		m1->m_len = len+tlen;
    570 		siz -= xfer;
    571 		cp += xfer;
    572 	}
    573 	*mb = m1;
    574 	*bpos = mtod(m1, caddr_t)+m1->m_len;
    575 	return (0);
    576 }
    577 
    578 /*
    579  * Called once to initialize data structures...
    580  */
    581 nfs_init()
    582 {
    583 	register int i;
    584 
    585 	nfsrtt.pos = 0;
    586 	rpc_vers = txdr_unsigned(RPC_VER2);
    587 	rpc_call = txdr_unsigned(RPC_CALL);
    588 	rpc_reply = txdr_unsigned(RPC_REPLY);
    589 	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
    590 	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
    591 	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
    592 	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
    593 	rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
    594 	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
    595 	rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
    596 	nfs_vers = txdr_unsigned(NFS_VER2);
    597 	nfs_prog = txdr_unsigned(NFS_PROG);
    598 	nfs_true = txdr_unsigned(TRUE);
    599 	nfs_false = txdr_unsigned(FALSE);
    600 	nfs_xdrneg1 = txdr_unsigned(-1);
    601 	/* Loop thru nfs procids */
    602 	for (i = 0; i < NFS_NPROCS; i++)
    603 		nfs_procids[i] = txdr_unsigned(i);
    604 #ifdef NFSCLIENT
    605 	/* Ensure async daemons disabled */
    606 	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
    607 		nfs_iodwant[i] = (struct proc *)0;
    608 	TAILQ_INIT(&nfs_bufq);
    609 	nfs_nhinit();			/* Init the nfsnode table */
    610 #endif /* NFSCLIENT */
    611 #ifdef NFSSERVER
    612 	nfsrv_init(0);			/* Init server data structures */
    613 	nfsrv_initcache();		/* Init the server request cache */
    614 #endif /* NFSSERVER */
    615 
    616 	/*
    617 	 * Initialize the nqnfs server stuff.
    618 	 */
    619 	if (nqnfsstarttime == 0) {
    620 		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
    621 			+ nqsrv_clockskew + nqsrv_writeslack;
    622 		NQLOADNOVRAM(nqnfsstarttime);
    623 		nqnfs_prog = txdr_unsigned(NQNFS_PROG);
    624 		nqnfs_vers = txdr_unsigned(NQNFS_VER1);
    625 		nqthead.th_head[0] = &nqthead;
    626 		nqthead.th_head[1] = &nqthead;
    627 		nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash);
    628 	}
    629 
    630 	/*
    631 	 * Initialize reply list and start timer
    632 	 */
    633 	nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh;
    634 	nfs_timer();
    635 }
    636 
    637 #ifdef NFSCLIENT
    638 /*
    639  * Attribute cache routines.
    640  * nfs_loadattrcache() - loads or updates the cache contents from attributes
    641  *	that are on the mbuf list
    642  * nfs_getattrcache() - returns valid attributes if found in cache, returns
    643  *	error otherwise
    644  */
    645 
    646 /*
    647  * Load the attribute cache (that lives in the nfsnode entry) with
    648  * the values on the mbuf list and
    649  * Iff vap not NULL
    650  *    copy the attributes to *vaper
    651  */
    652 nfs_loadattrcache(vpp, mdp, dposp, vaper)
    653 	struct vnode **vpp;
    654 	struct mbuf **mdp;
    655 	caddr_t *dposp;
    656 	struct vattr *vaper;
    657 {
    658 	register struct vnode *vp = *vpp;
    659 	register struct vattr *vap;
    660 	register struct nfsv2_fattr *fp;
    661 	extern int (**spec_nfsv2nodeop_p)();
    662 	register struct nfsnode *np, *nq, **nhpp;
    663 	register long t1;
    664 	caddr_t dpos, cp2;
    665 	int error = 0, isnq;
    666 	struct mbuf *md;
    667 	enum vtype vtyp;
    668 	u_short vmode;
    669 	long rdev;
    670 	struct timespec mtime;
    671 	struct vnode *nvp;
    672 
    673 	md = *mdp;
    674 	dpos = *dposp;
    675 	t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
    676 	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
    677 	if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2))
    678 		return (error);
    679 	fp = (struct nfsv2_fattr *)cp2;
    680 	vtyp = nfstov_type(fp->fa_type);
    681 	vmode = fxdr_unsigned(u_short, fp->fa_mode);
    682 	if (vtyp == VNON || vtyp == VREG)
    683 		vtyp = IFTOVT(vmode);
    684 	if (isnq) {
    685 		rdev = fxdr_unsigned(long, fp->fa_nqrdev);
    686 		fxdr_nqtime(&fp->fa_nqmtime, &mtime);
    687 	} else {
    688 		rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
    689 		fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
    690 	}
    691 	/*
    692 	 * If v_type == VNON it is a new node, so fill in the v_type,
    693 	 * n_mtime fields. Check to see if it represents a special
    694 	 * device, and if so, check for a possible alias. Once the
    695 	 * correct vnode has been obtained, fill in the rest of the
    696 	 * information.
    697 	 */
    698 	np = VTONFS(vp);
    699 	if (vp->v_type == VNON) {
    700 		if (vtyp == VCHR && rdev == 0xffffffff)
    701 			vp->v_type = vtyp = VFIFO;
    702 		else
    703 			vp->v_type = vtyp;
    704 		if (vp->v_type == VFIFO) {
    705 #ifdef FIFO
    706 			extern int (**fifo_nfsv2nodeop_p)();
    707 			vp->v_op = fifo_nfsv2nodeop_p;
    708 #else
    709 			return (EOPNOTSUPP);
    710 #endif /* FIFO */
    711 		}
    712 		if (vp->v_type == VCHR || vp->v_type == VBLK) {
    713 			vp->v_op = spec_nfsv2nodeop_p;
    714 			if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
    715 				/*
    716 				 * Discard unneeded vnode, but save its nfsnode.
    717 				 */
    718 				if (nq = np->n_forw)
    719 					nq->n_back = np->n_back;
    720 				*np->n_back = nq;
    721 				nvp->v_data = vp->v_data;
    722 				vp->v_data = NULL;
    723 				vp->v_op = spec_vnodeop_p;
    724 				vrele(vp);
    725 				vgone(vp);
    726 				/*
    727 				 * Reinitialize aliased node.
    728 				 */
    729 				np->n_vnode = nvp;
    730 				nhpp = (struct nfsnode **)nfs_hash(&np->n_fh);
    731 				if (nq = *nhpp)
    732 					nq->n_back = &np->n_forw;
    733 				np->n_forw = nq;
    734 				np->n_back = nhpp;
    735 				*nhpp = np;
    736 				*vpp = vp = nvp;
    737 			}
    738 		}
    739 		np->n_mtime = mtime.ts_sec;
    740 	}
    741 	vap = &np->n_vattr;
    742 	vap->va_type = vtyp;
    743 	vap->va_mode = (vmode & 07777);
    744 	vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
    745 	vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
    746 	vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
    747 	vap->va_rdev = (dev_t)rdev;
    748 	vap->va_mtime = mtime;
    749 	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
    750 	if (isnq) {
    751 		fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
    752 		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
    753 		fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
    754 		vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
    755 		fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
    756 		vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
    757 		fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
    758 		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
    759 		fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
    760 	} else {
    761 		vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
    762 		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
    763 		vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
    764 		vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
    765 		fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
    766 		vap->va_flags = 0;
    767 		fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime);
    768 		vap->va_gen = 0;
    769 		vap->va_filerev = 0;
    770 	}
    771 	if (vap->va_size != np->n_size) {
    772 		if (vap->va_type == VREG) {
    773 			if (np->n_flag & NMODIFIED) {
    774 				if (vap->va_size < np->n_size)
    775 					vap->va_size = np->n_size;
    776 				else
    777 					np->n_size = vap->va_size;
    778 			} else
    779 				np->n_size = vap->va_size;
    780 			vnode_pager_setsize(vp, (u_long)np->n_size);
    781 		} else
    782 			np->n_size = vap->va_size;
    783 	}
    784 	np->n_attrstamp = time.tv_sec;
    785 	*dposp = dpos;
    786 	*mdp = md;
    787 	if (vaper != NULL) {
    788 		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
    789 #ifdef notdef
    790 		if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
    791 		if (np->n_size > vap->va_size)
    792 			vaper->va_size = np->n_size;
    793 #endif
    794 		if (np->n_flag & NCHG) {
    795 			if (np->n_flag & NACC) {
    796 				vaper->va_atime.ts_sec = np->n_atim.tv_sec;
    797 				vaper->va_atime.ts_nsec =
    798 				    np->n_atim.tv_usec * 1000;
    799 			}
    800 			if (np->n_flag & NUPD) {
    801 				vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
    802 				vaper->va_mtime.ts_nsec =
    803 				    np->n_mtim.tv_usec * 1000;
    804 			}
    805 		}
    806 	}
    807 	return (0);
    808 }
    809 
    810 /*
    811  * Check the time stamp
    812  * If the cache is valid, copy contents to *vap and return 0
    813  * otherwise return an error
    814  */
    815 nfs_getattrcache(vp, vaper)
    816 	register struct vnode *vp;
    817 	struct vattr *vaper;
    818 {
    819 	register struct nfsnode *np = VTONFS(vp);
    820 	register struct vattr *vap;
    821 
    822 	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
    823 		if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
    824 			nfsstats.attrcache_misses++;
    825 			return (ENOENT);
    826 		}
    827 	} else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
    828 		nfsstats.attrcache_misses++;
    829 		return (ENOENT);
    830 	}
    831 	nfsstats.attrcache_hits++;
    832 	vap = &np->n_vattr;
    833 	if (vap->va_size != np->n_size) {
    834 		if (vap->va_type == VREG) {
    835 			if (np->n_flag & NMODIFIED) {
    836 				if (vap->va_size < np->n_size)
    837 					vap->va_size = np->n_size;
    838 				else
    839 					np->n_size = vap->va_size;
    840 			} else
    841 				np->n_size = vap->va_size;
    842 			vnode_pager_setsize(vp, (u_long)np->n_size);
    843 		} else
    844 			np->n_size = vap->va_size;
    845 	}
    846 	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
    847 #ifdef notdef
    848 	if ((np->n_flag & NMODIFIED) == 0) {
    849 		np->n_size = vaper->va_size;
    850 		vnode_pager_setsize(vp, (u_long)np->n_size);
    851 	} else if (np->n_size > vaper->va_size)
    852 	if (np->n_size > vaper->va_size)
    853 		vaper->va_size = np->n_size;
    854 #endif
    855 	if (np->n_flag & NCHG) {
    856 		if (np->n_flag & NACC) {
    857 			vaper->va_atime.ts_sec = np->n_atim.tv_sec;
    858 			vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
    859 		}
    860 		if (np->n_flag & NUPD) {
    861 			vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
    862 			vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
    863 		}
    864 	}
    865 	return (0);
    866 }
    867 #endif
    868 
    869 /*
    870  * Set up nameidata for a lookup() call and do it
    871  */
    872 nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
    873 	register struct nameidata *ndp;
    874 	fhandle_t *fhp;
    875 	int len;
    876 	struct nfssvc_sock *slp;
    877 	struct mbuf *nam;
    878 	struct mbuf **mdp;
    879 	caddr_t *dposp;
    880 	struct proc *p;
    881 {
    882 	register int i, rem;
    883 	register struct mbuf *md;
    884 	register char *fromcp, *tocp;
    885 	struct vnode *dp;
    886 	int error, rdonly;
    887 	struct componentname *cnp = &ndp->ni_cnd;
    888 
    889 	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
    890 	/*
    891 	 * Copy the name from the mbuf list to ndp->ni_pnbuf
    892 	 * and set the various ndp fields appropriately.
    893 	 */
    894 	fromcp = *dposp;
    895 	tocp = cnp->cn_pnbuf;
    896 	md = *mdp;
    897 	rem = mtod(md, caddr_t) + md->m_len - fromcp;
    898 	cnp->cn_hash = 0;
    899 	for (i = 0; i < len; i++) {
    900 		while (rem == 0) {
    901 			md = md->m_next;
    902 			if (md == NULL) {
    903 				error = EBADRPC;
    904 				goto out;
    905 			}
    906 			fromcp = mtod(md, caddr_t);
    907 			rem = md->m_len;
    908 		}
    909 		if (*fromcp == '\0' || *fromcp == '/') {
    910 			error = EINVAL;
    911 			goto out;
    912 		}
    913 		cnp->cn_hash += (unsigned char)*fromcp;
    914 		*tocp++ = *fromcp++;
    915 		rem--;
    916 	}
    917 	*tocp = '\0';
    918 	*mdp = md;
    919 	*dposp = fromcp;
    920 	len = nfsm_rndup(len)-len;
    921 	if (len > 0) {
    922 		if (rem >= len)
    923 			*dposp += len;
    924 		else if (error = nfs_adv(mdp, dposp, len, rem))
    925 			goto out;
    926 	}
    927 	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
    928 	cnp->cn_nameptr = cnp->cn_pnbuf;
    929 	/*
    930 	 * Extract and set starting directory.
    931 	 */
    932 	if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
    933 	    nam, &rdonly))
    934 		goto out;
    935 	if (dp->v_type != VDIR) {
    936 		vrele(dp);
    937 		error = ENOTDIR;
    938 		goto out;
    939 	}
    940 	ndp->ni_startdir = dp;
    941 	if (rdonly)
    942 		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
    943 	else
    944 		cnp->cn_flags |= NOCROSSMOUNT;
    945 	/*
    946 	 * And call lookup() to do the real work
    947 	 */
    948 	cnp->cn_proc = p;
    949 	if (error = lookup(ndp))
    950 		goto out;
    951 	/*
    952 	 * Check for encountering a symbolic link
    953 	 */
    954 	if (cnp->cn_flags & ISSYMLINK) {
    955 		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
    956 			vput(ndp->ni_dvp);
    957 		else
    958 			vrele(ndp->ni_dvp);
    959 		vput(ndp->ni_vp);
    960 		ndp->ni_vp = NULL;
    961 		error = EINVAL;
    962 		goto out;
    963 	}
    964 	/*
    965 	 * Check for saved name request
    966 	 */
    967 	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
    968 		cnp->cn_flags |= HASBUF;
    969 		return (0);
    970 	}
    971 out:
    972 	FREE(cnp->cn_pnbuf, M_NAMEI);
    973 	return (error);
    974 }
    975 
    976 /*
    977  * A fiddled version of m_adj() that ensures null fill to a long
    978  * boundary and only trims off the back end
    979  */
    980 void
    981 nfsm_adj(mp, len, nul)
    982 	struct mbuf *mp;
    983 	register int len;
    984 	int nul;
    985 {
    986 	register struct mbuf *m;
    987 	register int count, i;
    988 	register char *cp;
    989 
    990 	/*
    991 	 * Trim from tail.  Scan the mbuf chain,
    992 	 * calculating its length and finding the last mbuf.
    993 	 * If the adjustment only affects this mbuf, then just
    994 	 * adjust and return.  Otherwise, rescan and truncate
    995 	 * after the remaining size.
    996 	 */
    997 	count = 0;
    998 	m = mp;
    999 	for (;;) {
   1000 		count += m->m_len;
   1001 		if (m->m_next == (struct mbuf *)0)
   1002 			break;
   1003 		m = m->m_next;
   1004 	}
   1005 	if (m->m_len > len) {
   1006 		m->m_len -= len;
   1007 		if (nul > 0) {
   1008 			cp = mtod(m, caddr_t)+m->m_len-nul;
   1009 			for (i = 0; i < nul; i++)
   1010 				*cp++ = '\0';
   1011 		}
   1012 		return;
   1013 	}
   1014 	count -= len;
   1015 	if (count < 0)
   1016 		count = 0;
   1017 	/*
   1018 	 * Correct length for chain is "count".
   1019 	 * Find the mbuf with last data, adjust its length,
   1020 	 * and toss data from remaining mbufs on chain.
   1021 	 */
   1022 	for (m = mp; m; m = m->m_next) {
   1023 		if (m->m_len >= count) {
   1024 			m->m_len = count;
   1025 			if (nul > 0) {
   1026 				cp = mtod(m, caddr_t)+m->m_len-nul;
   1027 				for (i = 0; i < nul; i++)
   1028 					*cp++ = '\0';
   1029 			}
   1030 			break;
   1031 		}
   1032 		count -= m->m_len;
   1033 	}
   1034 	while (m = m->m_next)
   1035 		m->m_len = 0;
   1036 }
   1037 
   1038 /*
   1039  * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
   1040  * 	- look up fsid in mount list (if not found ret error)
   1041  *	- get vp and export rights by calling VFS_FHTOVP()
   1042  *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
   1043  *	- if not lockflag unlock it with VOP_UNLOCK()
   1044  */
   1045 nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
   1046 	fhandle_t *fhp;
   1047 	int lockflag;
   1048 	struct vnode **vpp;
   1049 	struct ucred *cred;
   1050 	struct nfssvc_sock *slp;
   1051 	struct mbuf *nam;
   1052 	int *rdonlyp;
   1053 {
   1054 	register struct mount *mp;
   1055 	register struct nfsuid *uidp;
   1056 	register int i;
   1057 	struct ucred *credanon;
   1058 	int error, exflags;
   1059 
   1060 	*vpp = (struct vnode *)0;
   1061 	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
   1062 		return (ESTALE);
   1063 	if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon))
   1064 		return (error);
   1065 	/*
   1066 	 * Check/setup credentials.
   1067 	 */
   1068 	if (exflags & MNT_EXKERB) {
   1069 		uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)];
   1070 		while (uidp) {
   1071 			if (uidp->nu_uid == cred->cr_uid)
   1072 				break;
   1073 			uidp = uidp->nu_hnext;
   1074 		}
   1075 		if (uidp) {
   1076 			cred->cr_uid = uidp->nu_cr.cr_uid;
   1077 			for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
   1078 				cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
   1079 			cred->cr_ngroups = i;
   1080 		} else {
   1081 			vput(*vpp);
   1082 			return (NQNFS_AUTHERR);
   1083 		}
   1084 	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
   1085 		cred->cr_uid = credanon->cr_uid;
   1086 		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
   1087 			cred->cr_groups[i] = credanon->cr_groups[i];
   1088 		cred->cr_ngroups = i;
   1089 	}
   1090 	if (exflags & MNT_EXRDONLY)
   1091 		*rdonlyp = 1;
   1092 	else
   1093 		*rdonlyp = 0;
   1094 	if (!lockflag)
   1095 		VOP_UNLOCK(*vpp);
   1096 	return (0);
   1097 }
   1098 
   1099 /*
   1100  * This function compares two net addresses by family and returns TRUE
   1101  * if they are the same host.
   1102  * If there is any doubt, return FALSE.
   1103  * The AF_INET family is handled as a special case so that address mbufs
   1104  * don't need to be saved to store "struct in_addr", which is only 4 bytes.
   1105  */
   1106 netaddr_match(family, haddr, nam)
   1107 	int family;
   1108 	union nethostaddr *haddr;
   1109 	struct mbuf *nam;
   1110 {
   1111 	register struct sockaddr_in *inetaddr;
   1112 
   1113 	switch (family) {
   1114 	case AF_INET:
   1115 		inetaddr = mtod(nam, struct sockaddr_in *);
   1116 		if (inetaddr->sin_family == AF_INET &&
   1117 		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
   1118 			return (1);
   1119 		break;
   1120 #ifdef ISO
   1121 	case AF_ISO:
   1122 	    {
   1123 		register struct sockaddr_iso *isoaddr1, *isoaddr2;
   1124 
   1125 		isoaddr1 = mtod(nam, struct sockaddr_iso *);
   1126 		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
   1127 		if (isoaddr1->siso_family == AF_ISO &&
   1128 		    isoaddr1->siso_nlen > 0 &&
   1129 		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
   1130 		    SAME_ISOADDR(isoaddr1, isoaddr2))
   1131 			return (1);
   1132 		break;
   1133 	    }
   1134 #endif	/* ISO */
   1135 	default:
   1136 		break;
   1137 	};
   1138 	return (0);
   1139 }
   1140