Commit | Line | Data |
---|---|---|
a2907882 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 | * | |
8 | * Redistribution and use in source and binary forms are permitted | |
9 | * provided that the above copyright notice and this paragraph are | |
10 | * duplicated in all such forms and that any documentation, | |
11 | * advertising materials, and other materials related to such | |
12 | * distribution and use acknowledge that the software was developed | |
13 | * by the University of California, Berkeley. The name of the | |
14 | * University may not be used to endorse or promote products derived | |
15 | * from this software without specific prior written permission. | |
16 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
17 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
19 | * | |
0bd503ad | 20 | * @(#)nfs_socket.c 7.4 (Berkeley) %G% |
a2907882 KM |
21 | */ |
22 | ||
23 | /* | |
24 | * Socket operations for use by nfs (similar to uipc_socket.c, but never | |
25 | * with copies to/from a uio vector) | |
26 | * NB: For now, they only work for UDP datagram sockets. | |
27 | * (Use on stream sockets would require some record boundary mark in the | |
28 | * stream such as Sun's RM (Section 3.2 of the Sun RPC Message Protocol | |
29 | * manual, in Networking on the Sun Workstation, Part #800-1324-03 | |
30 | * and different versions of send, receive and reply that do not assume | |
31 | * an atomic protocol | |
32 | */ | |
33 | ||
34 | #include "types.h" | |
35 | #include "param.h" | |
36 | #include "uio.h" | |
37 | #include "user.h" | |
38 | #include "mount.h" | |
39 | #include "kernel.h" | |
40 | #include "malloc.h" | |
41 | #include "mbuf.h" | |
42 | #include "vnode.h" | |
43 | #include "domain.h" | |
44 | #include "protosw.h" | |
45 | #include "socket.h" | |
46 | #include "socketvar.h" | |
47 | #include "netinet/in.h" | |
48 | #include "rpcv2.h" | |
49 | #include "nfsv2.h" | |
50 | #include "nfs.h" | |
51 | #include "xdr_subs.h" | |
52 | #include "nfsm_subs.h" | |
53 | #include "nfsmount.h" | |
54 | ||
55 | #define TRUE 1 | |
56 | ||
57 | /* set lock on sockbuf sb, sleep at neg prio */ | |
58 | #define nfs_sblock(sb) { \ | |
59 | while ((sb)->sb_flags & SB_LOCK) { \ | |
60 | (sb)->sb_flags |= SB_WANT; \ | |
61 | sleep((caddr_t)&(sb)->sb_flags, PZERO-1); \ | |
62 | } \ | |
63 | (sb)->sb_flags |= SB_LOCK; \ | |
64 | } | |
65 | ||
66 | /* | |
67 | * External data, mostly RPC constants in XDR form | |
68 | */ | |
69 | extern u_long rpc_reply, rpc_msgdenied, rpc_mismatch, rpc_vers, rpc_auth_unix, | |
70 | rpc_msgaccepted, rpc_call; | |
71 | extern u_long nfs_prog, nfs_vers; | |
72 | int nfsrv_null(), | |
73 | nfsrv_getattr(), | |
74 | nfsrv_setattr(), | |
75 | nfsrv_lookup(), | |
76 | nfsrv_readlink(), | |
77 | nfsrv_read(), | |
78 | nfsrv_write(), | |
79 | nfsrv_create(), | |
80 | nfsrv_remove(), | |
81 | nfsrv_rename(), | |
82 | nfsrv_link(), | |
83 | nfsrv_symlink(), | |
84 | nfsrv_mkdir(), | |
85 | nfsrv_rmdir(), | |
86 | nfsrv_readdir(), | |
87 | nfsrv_statfs(), | |
88 | nfsrv_noop(); | |
89 | ||
90 | int (*nfsrv_procs[NFS_NPROCS])() = { | |
91 | nfsrv_null, | |
92 | nfsrv_getattr, | |
93 | nfsrv_setattr, | |
94 | nfsrv_noop, | |
95 | nfsrv_lookup, | |
96 | nfsrv_readlink, | |
97 | nfsrv_read, | |
98 | nfsrv_noop, | |
99 | nfsrv_write, | |
100 | nfsrv_create, | |
101 | nfsrv_remove, | |
102 | nfsrv_rename, | |
103 | nfsrv_link, | |
104 | nfsrv_symlink, | |
105 | nfsrv_mkdir, | |
106 | nfsrv_rmdir, | |
107 | nfsrv_readdir, | |
108 | nfsrv_statfs, | |
109 | }; | |
110 | ||
111 | ||
112 | /* | |
113 | * This is a stripped down version of sosend() specific to | |
114 | * udp/ip and uses the mbuf list provdied | |
115 | */ | |
116 | nfs_udpsend(so, nam, top, flags, siz) | |
117 | register struct socket *so; | |
118 | struct mbuf *nam; | |
119 | struct mbuf *top; | |
120 | int flags; | |
121 | int siz; | |
122 | { | |
123 | register int space; | |
0bd503ad | 124 | int error = 0, s, dontroute; |
a2907882 KM |
125 | |
126 | dontroute = | |
127 | (flags & MSG_DONTROUTE) && (so->so_options & SO_DONTROUTE) == 0 && | |
128 | (so->so_proto->pr_flags & PR_ATOMIC); | |
129 | #define snderr(errno) { error = errno; splx(s); goto release; } | |
130 | ||
131 | #ifdef MGETHDR | |
132 | top->m_pkthdr.len = siz; | |
133 | #endif | |
134 | restart: | |
135 | nfs_sblock(&so->so_snd); | |
136 | s = splnet(); | |
137 | if (so->so_state & SS_CANTSENDMORE) | |
138 | snderr(EPIPE); | |
139 | if (so->so_error) | |
140 | snderr(so->so_error); | |
141 | space = sbspace(&so->so_snd); | |
142 | if (space < siz) { | |
143 | sbunlock(&so->so_snd); | |
144 | nfs_sbwait(&so->so_snd); | |
145 | splx(s); | |
146 | goto restart; | |
147 | } | |
148 | splx(s); | |
149 | if (dontroute) | |
150 | so->so_options |= SO_DONTROUTE; | |
151 | s = splnet(); /* XXX */ | |
152 | error = (*so->so_proto->pr_usrreq)(so, | |
153 | PRU_SEND, | |
154 | top, (caddr_t)nam, (struct mbuf *)0, (struct mbuf *)0); | |
155 | splx(s); | |
156 | if (dontroute) | |
157 | so->so_options &= ~SO_DONTROUTE; | |
158 | top = (struct mbuf *)0; | |
159 | ||
160 | release: | |
161 | sbunlock(&so->so_snd); | |
162 | if (top) | |
163 | m_freem(top); | |
164 | return (error); | |
165 | } | |
166 | ||
167 | /* | |
168 | * This is a stripped down udp specific version of soreceive() | |
169 | */ | |
170 | nfs_udpreceive(so, aname, mp) | |
171 | register struct socket *so; | |
172 | struct mbuf **aname; | |
173 | struct mbuf **mp; | |
174 | { | |
175 | register struct mbuf *m; | |
176 | int s, error = 0; | |
a2907882 KM |
177 | struct mbuf *nextrecord; |
178 | ||
179 | if (aname) | |
180 | *aname = 0; | |
181 | ||
182 | restart: | |
183 | sblock(&so->so_rcv); | |
184 | s = splnet(); | |
185 | ||
186 | if (so->so_rcv.sb_cc == 0) { | |
187 | if (so->so_error) { | |
188 | error = so->so_error; | |
189 | so->so_error = 0; | |
190 | goto release; | |
191 | } | |
192 | if (so->so_state & SS_CANTRCVMORE) | |
193 | goto release; | |
194 | sbunlock(&so->so_rcv); | |
195 | sbwait(&so->so_rcv); | |
196 | splx(s); | |
197 | goto restart; | |
198 | } | |
199 | m = so->so_rcv.sb_mb; | |
200 | if (m == 0) | |
201 | panic("nfs_receive 1"); | |
202 | nextrecord = m->m_nextpkt; | |
203 | if (m->m_type != MT_SONAME) | |
204 | panic("nfs_receive 1a"); | |
205 | sbfree(&so->so_rcv, m); | |
206 | if (aname) { | |
207 | *aname = m; | |
208 | so->so_rcv.sb_mb = m->m_next; | |
209 | m->m_next = 0; | |
210 | m = so->so_rcv.sb_mb; | |
211 | } else { | |
212 | MFREE(m, so->so_rcv.sb_mb); | |
213 | m = so->so_rcv.sb_mb; | |
214 | } | |
215 | if (m && m->m_type == MT_RIGHTS) | |
216 | panic("nfs_receive 2"); | |
217 | if (m && m->m_type == MT_CONTROL) { | |
218 | sbfree(&so->so_rcv, m); | |
219 | MFREE(m, so->so_rcv.sb_mb); | |
220 | m = so->so_rcv.sb_mb; | |
221 | } | |
222 | *mp = m; | |
223 | while (m) { | |
224 | if (m->m_type != MT_DATA && m->m_type != MT_HEADER) | |
225 | panic("nfs_receive 3"); | |
226 | sbfree(&so->so_rcv, m); | |
227 | m = so->so_rcv.sb_mb = m->m_next; | |
228 | } | |
229 | so->so_rcv.sb_mb = nextrecord; | |
230 | so->so_state &= ~SS_RCVATMARK; /* Necessary ?? */ | |
231 | release: | |
232 | sbunlock(&so->so_rcv); | |
233 | splx(s); | |
234 | return (error); | |
235 | } | |
236 | ||
237 | struct nfsreq nfsreqh = { | |
238 | (struct nfsreq *)0, | |
239 | (struct nfsreq *)0, | |
240 | (struct mbuf *)0, | |
241 | (struct mbuf *)0, | |
242 | (struct nfsmount *)0, | |
243 | 0, 0, 0, 0, 0, | |
244 | }; | |
245 | ||
246 | struct rpc_replyhead { | |
247 | u_long r_xid; | |
248 | u_long r_rep; | |
249 | }; | |
250 | ||
251 | /* | |
252 | * Implement receipt of reply on a socket. | |
253 | * We depend on the way that records are added to the sockbuf | |
254 | * by sbappend*. In particular, each record (mbufs linked through m_next) | |
255 | * must begin with an address, followed by optional MT_CONTROL mbuf | |
256 | * and then zero or more mbufs of data. | |
257 | * Although the sockbuf is locked, new data may still be appended, | |
258 | * and thus we must maintain consistency of the sockbuf during that time. | |
259 | * We must search through the list of received datagrams matching them | |
260 | * with outstanding requests using the xid, until ours is found. | |
261 | */ | |
0bd503ad | 262 | /* ARGSUSED */ |
ffe6f482 | 263 | nfs_udpreply(so, mntp, myrep) |
a2907882 KM |
264 | register struct socket *so; |
265 | struct nfsmount *mntp; | |
ffe6f482 | 266 | struct nfsreq *myrep; |
a2907882 KM |
267 | { |
268 | register struct mbuf *m; | |
269 | register struct nfsreq *rep; | |
270 | register int error = 0, s; | |
a2907882 | 271 | struct mbuf *nextrecord; |
ffe6f482 KM |
272 | struct sockaddr_in *saddr; |
273 | u_long inaddr; | |
a2907882 KM |
274 | struct rpc_replyhead replyh; |
275 | struct mbuf *mp; | |
276 | char *cp; | |
277 | int cnt, xfer; | |
278 | int found; | |
279 | ||
280 | restart: | |
ffe6f482 | 281 | nfs_sblock(&so->so_rcv); |
a2907882 | 282 | /* Already received, bye bye */ |
ffe6f482 KM |
283 | if (myrep->r_mrep != NULL) { |
284 | sbunlock(&so->so_rcv); | |
a2907882 | 285 | return (0); |
ffe6f482 | 286 | } |
a2907882 | 287 | /* If a soft mount and we have run out of retries */ |
ffe6f482 KM |
288 | if (myrep->r_retry == 0 && myrep->r_timer == 0) { |
289 | sbunlock(&so->so_rcv); | |
a2907882 | 290 | return (ETIMEDOUT); |
ffe6f482 | 291 | } |
a2907882 KM |
292 | s = splnet(); |
293 | ||
ffe6f482 KM |
294 | m = so->so_rcv.sb_mb; |
295 | if (m == 0) { | |
296 | if (so->so_rcv.sb_cc) | |
297 | panic("nfs_soreply 1"); | |
a2907882 KM |
298 | if (so->so_error) { |
299 | error = so->so_error; | |
300 | so->so_error = 0; | |
301 | goto release; | |
302 | } | |
303 | if (so->so_state & SS_CANTRCVMORE) | |
304 | goto release; | |
305 | sbunlock(&so->so_rcv); | |
306 | nfs_sbwait(&so->so_rcv); | |
307 | splx(s); | |
308 | goto restart; | |
309 | } | |
a2907882 KM |
310 | nextrecord = m->m_nextpkt; |
311 | ||
312 | /* | |
313 | * Take off the address, check for rights and ditch any control | |
314 | * mbufs. | |
315 | */ | |
316 | if (m->m_type != MT_SONAME) | |
317 | panic("nfs reply SONAME"); | |
ffe6f482 KM |
318 | saddr = mtod(m, struct sockaddr_in *); |
319 | inaddr = saddr->sin_addr.s_addr; | |
a2907882 KM |
320 | sbfree(&so->so_rcv, m); |
321 | MFREE(m, so->so_rcv.sb_mb); | |
322 | m = so->so_rcv.sb_mb; | |
323 | if (m && m->m_type == MT_RIGHTS) | |
324 | panic("nfs reply RIGHTS"); | |
325 | if (m && m->m_type == MT_CONTROL) { | |
326 | sbfree(&so->so_rcv, m); | |
327 | MFREE(m, so->so_rcv.sb_mb); | |
328 | m = so->so_rcv.sb_mb; | |
329 | } | |
ffe6f482 | 330 | if (m) { |
a2907882 | 331 | m->m_nextpkt = nextrecord; |
ffe6f482 KM |
332 | } else { |
333 | so->so_rcv.sb_mb = nextrecord; | |
a2907882 KM |
334 | sbunlock(&so->so_rcv); |
335 | splx(s); | |
336 | goto restart; | |
337 | } | |
338 | ||
339 | /* | |
340 | * Get the xid and check that it is an rpc reply | |
341 | */ | |
342 | mp = m; | |
343 | if (m->m_len >= 2*NFSX_UNSIGNED) | |
344 | bcopy(mtod(m, caddr_t), (caddr_t)&replyh, 2*NFSX_UNSIGNED); | |
345 | else { | |
346 | cnt = 2*NFSX_UNSIGNED; | |
347 | cp = (caddr_t)&replyh; | |
348 | while (mp && cnt > 0) { | |
349 | if (mp->m_len > 0) { | |
350 | xfer = (mp->m_len >= cnt) ? cnt : mp->m_len; | |
351 | bcopy(mtod(mp, caddr_t), cp, xfer); | |
352 | cnt -= xfer; | |
353 | cp += xfer; | |
354 | } | |
355 | if (cnt > 0) | |
356 | mp = mp->m_next; | |
357 | } | |
358 | } | |
ffe6f482 | 359 | found = 0; |
a2907882 KM |
360 | if (replyh.r_rep != rpc_reply || mp == NULL) |
361 | goto dropit; | |
362 | /* | |
363 | * Loop through the request list to match up the reply | |
364 | * Iff no match, just drop the datagram | |
365 | */ | |
ffe6f482 KM |
366 | rep = nfsreqh.r_next; |
367 | while (!found && rep != &nfsreqh) { | |
368 | if (rep->r_mrep == NULL && replyh.r_xid == rep->r_xid && | |
369 | inaddr == rep->r_inaddr) { | |
a2907882 KM |
370 | /* Found it.. */ |
371 | rep->r_mrep = m; | |
372 | while (m) { | |
373 | if (m->m_type != MT_DATA && m->m_type != MT_HEADER) | |
374 | panic("nfs_soreply 3"); | |
375 | sbfree(&so->so_rcv, m); | |
376 | m = so->so_rcv.sb_mb = m->m_next; | |
377 | } | |
378 | so->so_rcv.sb_mb = nextrecord; | |
379 | if (rep == myrep) | |
380 | goto release; | |
381 | found++; | |
382 | } | |
383 | rep = rep->r_next; | |
384 | } | |
385 | /* Iff not matched to request, drop it */ | |
386 | dropit: | |
ffe6f482 | 387 | if (!found) { |
a2907882 | 388 | sbdroprecord(&so->so_rcv); |
ffe6f482 KM |
389 | } else if (so->so_rcv.sb_flags & SB_WAIT) { |
390 | so->so_rcv.sb_flags &= ~SB_WAIT; | |
391 | wakeup((caddr_t)&so->so_rcv.sb_cc); | |
392 | } | |
a2907882 KM |
393 | sbunlock(&so->so_rcv); |
394 | splx(s); | |
395 | goto restart; | |
396 | release: | |
397 | sbunlock(&so->so_rcv); | |
398 | splx(s); | |
399 | return (error); | |
400 | } | |
401 | ||
402 | /* | |
403 | * nfs_request - goes something like this | |
404 | * - fill in request struct | |
405 | * - links it into list | |
406 | * - calls nfs_sosend() for first transmit | |
407 | * - calls nfs_soreceive() to get reply | |
408 | * - break down rpc header and return with nfs reply pointed to | |
409 | * by mrep or error | |
410 | * nb: always frees up mreq mbuf list | |
411 | */ | |
412 | nfs_request(vp, mreq, xid, mp, mrp, mdp, dposp) | |
413 | struct vnode *vp; | |
414 | struct mbuf *mreq; | |
415 | u_long xid; | |
416 | struct mount *mp; | |
417 | struct mbuf **mrp; | |
418 | struct mbuf **mdp; | |
419 | caddr_t *dposp; | |
420 | { | |
421 | register struct mbuf *m, *mrep; | |
422 | register struct nfsreq *rep; | |
423 | register u_long *p; | |
424 | register int len; | |
425 | struct nfsmount *mntp; | |
426 | struct mbuf *md; | |
ffe6f482 KM |
427 | struct sockaddr_in *saddr; |
428 | struct nfsreq *reph; | |
a2907882 KM |
429 | caddr_t dpos; |
430 | char *cp2; | |
431 | int t1; | |
432 | int s; | |
433 | int error; | |
434 | ||
435 | mntp = vfs_to_nfs(mp); | |
436 | m = mreq; | |
437 | MALLOC(rep, struct nfsreq *, sizeof(struct nfsreq), M_NFSREQ, M_WAITOK); | |
438 | rep->r_xid = xid; | |
439 | rep->r_mntp = mntp; | |
ffe6f482 KM |
440 | saddr = mtod(mntp->nm_sockaddr, struct sockaddr_in *); |
441 | rep->r_inaddr = saddr->sin_addr.s_addr; | |
a2907882 KM |
442 | rep->r_vp = vp; |
443 | if (mntp->nm_flag & NFSMNT_SOFT) | |
444 | rep->r_retry = mntp->nm_retrans; | |
445 | else | |
446 | rep->r_retry = VNOVAL; | |
447 | rep->r_mrep = NULL; | |
448 | rep->r_mreq = m; | |
449 | rep->r_timer = rep->r_timeout = mntp->nm_timeo; | |
450 | len = 0; | |
451 | while (m) { | |
452 | len += m->m_len; | |
453 | m = m->m_next; | |
454 | } | |
455 | rep->r_msiz = len; | |
456 | m = NFSMCOPY(mreq, 0, M_COPYALL, M_WAIT); | |
457 | ||
458 | /* Chain it into list of outstanding requests */ | |
ffe6f482 | 459 | reph = &nfsreqh; |
a2907882 | 460 | s = splnet(); |
ffe6f482 KM |
461 | if (reph->r_prev == NULL) { |
462 | reph->r_next = rep; | |
463 | rep->r_prev = reph; | |
464 | } else { | |
465 | reph->r_prev->r_next = rep; | |
466 | rep->r_prev = reph->r_prev; | |
467 | } | |
468 | reph->r_prev = rep; | |
469 | rep->r_next = reph; | |
a2907882 KM |
470 | splx(s); |
471 | ||
472 | /* | |
473 | * Iff the NFSMCOPY above succeeded, send it off... | |
474 | * otherwise the timer will retransmit later | |
475 | */ | |
476 | if (m != NULL) | |
477 | error = nfs_udpsend(mntp->nm_so, (struct mbuf *)0, m, 0, len); | |
ffe6f482 | 478 | error = nfs_udpreply(mntp->nm_so, mntp, rep); |
a2907882 KM |
479 | |
480 | s = splnet(); | |
481 | rep->r_prev->r_next = rep->r_next; | |
ffe6f482 | 482 | rep->r_next->r_prev = rep->r_prev; |
a2907882 KM |
483 | splx(s); |
484 | m_freem(rep->r_mreq); | |
485 | mrep = md = rep->r_mrep; | |
486 | FREE((caddr_t)rep, M_NFSREQ); | |
487 | if (error) | |
488 | return (error); | |
489 | ||
490 | /* | |
491 | * break down the rpc header and check if ok | |
492 | */ | |
493 | dpos = mtod(md, caddr_t); | |
494 | nfsm_disect(p, u_long *, 5*NFSX_UNSIGNED); | |
495 | p += 2; | |
496 | if (*p++ == rpc_msgdenied) { | |
497 | if (*p == rpc_mismatch) | |
498 | error = EOPNOTSUPP; | |
499 | else | |
500 | error = EACCES; | |
501 | m_freem(mrep); | |
502 | return (error); | |
503 | } | |
504 | /* | |
505 | * skip over the auth_verf, someday we may want to cache auth_short's | |
506 | * for nfs_reqhead(), but for now just dump it | |
507 | */ | |
508 | if (*++p != 0) { | |
509 | len = nfsm_rndup(fxdr_unsigned(long, *p)); | |
510 | nfsm_adv(len); | |
511 | } | |
512 | nfsm_disect(p, u_long *, NFSX_UNSIGNED); | |
513 | /* 0 == ok */ | |
514 | if (*p == 0) { | |
515 | nfsm_disect(p, u_long *, NFSX_UNSIGNED); | |
516 | if (*p != 0) { | |
517 | error = fxdr_unsigned(int, *p); | |
518 | m_freem(mrep); | |
519 | return (error); | |
520 | } | |
521 | *mrp = mrep; | |
522 | *mdp = md; | |
523 | *dposp = dpos; | |
524 | return (0); | |
525 | } | |
526 | m_freem(mrep); | |
527 | return (EPROTONOSUPPORT); | |
528 | nfsmout: | |
529 | return (error); | |
530 | } | |
531 | ||
532 | /* | |
533 | * Get a request for the server main loop | |
534 | * - receive a request via. nfs_soreceive() | |
535 | * - verify it | |
536 | * - fill in the cred struct. | |
537 | */ | |
538 | nfs_getreq(so, prog, vers, maxproc, nam, mrp, mdp, dposp, retxid, proc, cr) | |
539 | struct socket *so; | |
540 | u_long prog; | |
541 | u_long vers; | |
542 | int maxproc; | |
543 | struct mbuf **nam; | |
544 | struct mbuf **mrp; | |
545 | struct mbuf **mdp; | |
546 | caddr_t *dposp; | |
547 | u_long *retxid; | |
548 | u_long *proc; | |
549 | register struct ucred *cr; | |
550 | { | |
551 | register int i; | |
0bd503ad KM |
552 | register u_long *p; |
553 | register long t1; | |
554 | caddr_t dpos, cp2; | |
555 | int error = 0; | |
556 | struct mbuf *mrep, *md; | |
557 | int len; | |
a2907882 KM |
558 | |
559 | if (error = nfs_udpreceive(so, nam, &mrep)) | |
560 | return (error); | |
561 | md = mrep; | |
562 | dpos = mtod(mrep, caddr_t); | |
563 | nfsm_disect(p, u_long *, 10*NFSX_UNSIGNED); | |
564 | *retxid = *p++; | |
565 | if (*p++ != rpc_call) { | |
566 | m_freem(mrep); | |
567 | return (ERPCMISMATCH); | |
568 | } | |
569 | if (*p++ != rpc_vers) { | |
570 | m_freem(mrep); | |
571 | return (ERPCMISMATCH); | |
572 | } | |
573 | if (*p++ != prog) { | |
574 | m_freem(mrep); | |
575 | return (EPROGUNAVAIL); | |
576 | } | |
577 | if (*p++ != vers) { | |
578 | m_freem(mrep); | |
579 | return (EPROGMISMATCH); | |
580 | } | |
581 | *proc = fxdr_unsigned(u_long, *p++); | |
582 | if (*proc == NFSPROC_NULL) { | |
583 | *mrp = mrep; | |
584 | return (0); | |
585 | } | |
586 | if (*proc > maxproc || *p++ != rpc_auth_unix) { | |
587 | m_freem(mrep); | |
588 | return (EPROCUNAVAIL); | |
589 | } | |
0bd503ad KM |
590 | (void) fxdr_unsigned(int, *p++); |
591 | len = fxdr_unsigned(int, *++p); | |
592 | nfsm_adv(nfsm_rndup(len)); | |
a2907882 KM |
593 | nfsm_disect(p, u_long *, 3*NFSX_UNSIGNED); |
594 | cr->cr_uid = fxdr_unsigned(uid_t, *p++); | |
595 | cr->cr_gid = fxdr_unsigned(gid_t, *p++); | |
0bd503ad KM |
596 | len = fxdr_unsigned(int, *p); |
597 | if (len > 10) { | |
a2907882 KM |
598 | m_freem(mrep); |
599 | return (EBADRPC); | |
600 | } | |
0bd503ad KM |
601 | nfsm_disect(p, u_long *, (len + 2)*NFSX_UNSIGNED); |
602 | for (i = 1; i <= len; i++) | |
a2907882 | 603 | cr->cr_groups[i] = fxdr_unsigned(gid_t, *p++); |
0bd503ad | 604 | cr->cr_ngroups = len + 1; |
a2907882 KM |
605 | /* |
606 | * Do we have any use for the verifier. | |
607 | * According to the "Remote Procedure Call Protocol Spec." it | |
608 | * should be AUTH_NULL, but some clients make it AUTH_UNIX? | |
609 | * For now, just skip over it | |
610 | */ | |
0bd503ad KM |
611 | len = fxdr_unsigned(int, *++p); |
612 | if (len > 0) | |
613 | nfsm_adv(nfsm_rndup(len)); | |
a2907882 KM |
614 | *mrp = mrep; |
615 | *mdp = md; | |
616 | *dposp = dpos; | |
617 | return (0); | |
618 | nfsmout: | |
619 | return (error); | |
620 | } | |
621 | ||
622 | /* | |
623 | * Generate the rpc reply header | |
624 | * siz arg. is used to decide if adding a cluster is worthwhile | |
625 | */ | |
626 | nfs_rephead(siz, retxid, err, mrq, mbp, bposp) | |
627 | int siz; | |
628 | u_long retxid; | |
629 | int err; | |
630 | struct mbuf **mrq; | |
631 | struct mbuf **mbp; | |
632 | caddr_t *bposp; | |
633 | { | |
0bd503ad KM |
634 | register u_long *p; |
635 | register long t1; | |
636 | caddr_t bpos; | |
637 | struct mbuf *mreq, *mb, *mb2; | |
a2907882 KM |
638 | |
639 | NFSMGETHDR(mreq); | |
640 | mb = mreq; | |
641 | if ((siz+RPC_REPLYSIZ) > MHLEN) | |
642 | NFSMCLGET(mreq, M_WAIT); | |
643 | p = mtod(mreq, u_long *); | |
644 | mreq->m_len = 6*NFSX_UNSIGNED; | |
645 | bpos = ((caddr_t)p)+mreq->m_len; | |
646 | *p++ = retxid; | |
647 | *p++ = rpc_reply; | |
648 | if (err == ERPCMISMATCH) { | |
649 | *p++ = rpc_msgdenied; | |
650 | *p++ = rpc_mismatch; | |
651 | *p++ = txdr_unsigned(2); | |
652 | *p = txdr_unsigned(2); | |
653 | } else { | |
654 | *p++ = rpc_msgaccepted; | |
655 | *p++ = 0; | |
656 | *p++ = 0; | |
657 | switch (err) { | |
658 | case EPROGUNAVAIL: | |
659 | *p = txdr_unsigned(RPC_PROGUNAVAIL); | |
660 | break; | |
661 | case EPROGMISMATCH: | |
662 | *p = txdr_unsigned(RPC_PROGMISMATCH); | |
663 | nfsm_build(p, u_long *, 2*NFSX_UNSIGNED); | |
664 | *p++ = txdr_unsigned(2); | |
665 | *p = txdr_unsigned(2); /* someday 3 */ | |
666 | break; | |
667 | case EPROCUNAVAIL: | |
668 | *p = txdr_unsigned(RPC_PROCUNAVAIL); | |
669 | break; | |
670 | default: | |
671 | *p = 0; | |
672 | if (err != VNOVAL) { | |
673 | nfsm_build(p, u_long *, NFSX_UNSIGNED); | |
674 | *p = txdr_unsigned(err); | |
675 | } | |
676 | break; | |
677 | }; | |
678 | } | |
679 | *mrq = mreq; | |
680 | *mbp = mb; | |
681 | *bposp = bpos; | |
682 | if (err != 0 && err != VNOVAL) | |
683 | nfsstats.srvrpc_errs++; | |
684 | return (0); | |
685 | } | |
686 | ||
687 | /* | |
688 | * Nfs timer routine | |
689 | * Scan the nfsreq list and retranmit any requests that have timed out | |
690 | * To avoid retransmission attempts on STREAM sockets (in the future) make | |
691 | * sure to set the r_retry field to 0. | |
692 | */ | |
693 | nfs_timer() | |
694 | { | |
695 | register struct nfsreq *rep; | |
696 | register struct mbuf *m; | |
697 | register struct socket *so; | |
0bd503ad | 698 | int s; |
a2907882 KM |
699 | |
700 | s = splnet(); | |
701 | rep = nfsreqh.r_next; | |
ffe6f482 | 702 | while (rep && rep != &nfsreqh) { |
a2907882 KM |
703 | if (rep->r_timer > 0) |
704 | rep->r_timer--; | |
705 | else if (rep->r_mrep == NULL && rep->r_retry > 0) { | |
706 | so = rep->r_mntp->nm_so; | |
707 | if ((so->so_state & SS_CANTSENDMORE) == 0 && | |
708 | !so->so_error && | |
709 | sbspace(&so->so_snd) >= rep->r_msiz) { | |
710 | m = NFSMCOPY(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT); | |
711 | if (m != NULL) { | |
712 | nfsstats.rpcretries++; | |
36c3043b KM |
713 | rep->r_timeout <<= 2; /* x4 backoff */ |
714 | if (rep->r_timeout > NFS_MAXTIMEO) | |
715 | rep->r_timeout = NFS_MAXTIMEO; | |
a2907882 KM |
716 | rep->r_timer = rep->r_timeout; |
717 | if (rep->r_retry != VNOVAL) | |
718 | rep->r_retry--; | |
719 | #ifdef MGETHDR | |
720 | m->m_pkthdr.len = rep->r_msiz; | |
721 | #endif | |
722 | (*so->so_proto->pr_usrreq)(so, PRU_SEND, | |
723 | m, (caddr_t)0, (struct mbuf *)0, | |
724 | (struct mbuf *)0); | |
725 | } | |
726 | } | |
727 | } | |
728 | rep = rep->r_next; | |
729 | } | |
730 | splx(s); | |
36c3043b | 731 | timeout(nfs_timer, (caddr_t)0, hz/10); |
a2907882 KM |
732 | } |
733 | ||
734 | /* | |
735 | * nfs_sbwait() is simply sbwait() but at a negative priority so that it | |
736 | * can not be interrupted by a signal. | |
737 | */ | |
738 | nfs_sbwait(sb) | |
739 | struct sockbuf *sb; | |
740 | { | |
741 | sb->sb_flags |= SB_WAIT; | |
ffe6f482 | 742 | sleep((caddr_t)&sb->sb_cc, PZERO-2); |
a2907882 | 743 | } |