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