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