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