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