]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/rpc/rpcclnt.c
This commit was generated by cvs2svn to compensate for changes in r168305,
[FreeBSD/FreeBSD.git] / sys / rpc / rpcclnt.c
1 /* $FreeBSD$ */
2 /* $Id: rpcclnt.c,v 1.9 2003/11/05 14:59:03 rees Exp $ */
3
4 /*-
5  * copyright (c) 2003
6  * the regents of the university of michigan
7  * all rights reserved
8  * 
9  * permission is granted to use, copy, create derivative works and redistribute
10  * this software and such derivative works for any purpose, so long as the name
11  * of the university of michigan is not used in any advertising or publicity
12  * pertaining to the use or distribution of this software without specific,
13  * written prior authorization.  if the above copyright notice or any other
14  * identification of the university of michigan is included in any copy of any
15  * portion of this software, then the disclaimer below must also be included.
16  * 
17  * this software is provided as is, without representation from the university
18  * of michigan as to its fitness for any purpose, and without warranty by the
19  * university of michigan of any kind, either express or implied, including
20  * without limitation the implied warranties of merchantability and fitness for
21  * a particular purpose. the regents of the university of michigan shall not be
22  * liable for any damages, including special, indirect, incidental, or
23  * consequential damages, with respect to any claim arising out of or in
24  * connection with the use of the software, even if it has been or is hereafter
25  * advised of the possibility of such damages.
26  */
27
28 /*-
29  * Copyright (c) 1989, 1991, 1993, 1995 The Regents of the University of
30  * California.  All rights reserved.
31  * 
32  * This code is derived from software contributed to Berkeley by Rick Macklem at
33  * The University of Guelph.
34  * 
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions are
37  * met: 1. Redistributions of source code must retain the above copyright
38  * notice, this list of conditions and the following disclaimer. 2.
39  * Redistributions in binary form must reproduce the above copyright notice,
40  * this list of conditions and the following disclaimer in the documentation
41  * and/or other materials provided with the distribution. 3. All advertising
42  * materials mentioning features or use of this software must display the
43  * following acknowledgement: This product includes software developed by the
44  * University of California, Berkeley and its contributors. 4. Neither the
45  * name of the University nor the names of its contributors may be used to
46  * endorse or promote products derived from this software without specific
47  * prior written permission.
48  * 
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
50  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
51  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
52  * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
53  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
55  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
56  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  * 
61  * @(#)nfs_socket.c     8.5 (Berkeley) 3/30/95
62  */
63
64 /* XXX: kill ugly debug strings */
65 /* XXX: get rid of proct, as it is not even being used... (or keep it so v{2,3}
66  *      can run, but clean it up! */
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/proc.h>
71 #include <sys/mount.h>
72 #include <sys/kernel.h>
73 #include <sys/mbuf.h>
74 #include <sys/syslog.h>
75 #include <sys/malloc.h>
76 #include <sys/uio.h>
77 #include <sys/lock.h>
78 #include <sys/signalvar.h>
79 #include <sys/sysent.h>
80 #include <sys/syscall.h>
81 #include <sys/sysctl.h>
82
83 #include <sys/domain.h>
84 #include <sys/protosw.h>
85 #include <sys/socket.h>
86 #include <sys/socketvar.h>
87 #include <sys/mutex.h>
88
89 #include <netinet/in.h>
90 #include <netinet/tcp.h>
91
92 #include <nfs/rpcv2.h>
93
94 #include <rpc/rpcm_subs.h>
95 #include <rpc/rpcclnt.h>
96
97 /* memory management */
98 #ifdef __OpenBSD__
99 struct pool     rpctask_pool;
100 struct pool     rpcclnt_pool;
101 #define RPCTASKPOOL_LWM 10
102 #define RPCTASKPOOL_HWM 40
103 #else
104 static          MALLOC_DEFINE(M_RPC, "rpcclnt", "rpc state");
105 #endif
106
107 #define RPC_RETURN(X) do { RPCDEBUG("returning %d", X); return X; }while(0)
108
109 /*
110  * Estimate rto for an nfs rpc sent via. an unreliable datagram. Use the mean
111  * and mean deviation of rtt for the appropriate type of rpc for the frequent
112  * rpcs and a default for the others. The justification for doing "other"
113  * this way is that these rpcs happen so infrequently that timer est. would
114  * probably be stale. Also, since many of these rpcs are non-idempotent, a
115  * conservative timeout is desired. getattr, lookup - A+2D read, write     -
116  * A+4D other           - nm_timeo
117  */
118 #define RPC_RTO(n, t) \
119         ((t) == 0 ? (n)->rc_timeo : \
120          ((t) < 3 ? \
121           (((((n)->rc_srtt[t-1] + 3) >> 2) + (n)->rc_sdrtt[t-1] + 1) >> 1) : \
122           ((((n)->rc_srtt[t-1] + 7) >> 3) + (n)->rc_sdrtt[t-1] + 1)))
123
124 #define RPC_SRTT(s,r)   (r)->r_rpcclnt->rc_srtt[rpcclnt_proct((s),\
125                                 (r)->r_procnum) - 1]
126
127 #define RPC_SDRTT(s,r)  (r)->r_rpcclnt->rc_sdrtt[rpcclnt_proct((s),\
128                                 (r)->r_procnum) - 1]
129
130
131 /*
132  * There is a congestion window for outstanding rpcs maintained per mount
133  * point. The cwnd size is adjusted in roughly the way that: Van Jacobson,
134  * Congestion avoidance and Control, In "Proceedings of SIGCOMM '88". ACM,
135  * August 1988. describes for TCP. The cwnd size is chopped in half on a
136  * retransmit timeout and incremented by 1/cwnd when each rpc reply is
137  * received and a full cwnd of rpcs is in progress. (The sent count and cwnd
138  * are scaled for integer arith.) Variants of "slow start" were tried and
139  * were found to be too much of a performance hit (ave. rtt 3 times larger),
140  * I suspect due to the large rtt that nfs rpcs have.
141  */
142 #define RPC_CWNDSCALE   256
143 #define RPC_MAXCWND     (RPC_CWNDSCALE * 32)
144 static const int      rpcclnt_backoff[8] = {2, 4, 8, 16, 32, 64, 128, 256,};
145
146 /* XXX ugly debug strings */
147 #define RPC_ERRSTR_ACCEPTED_SIZE 6
148 char *rpc_errstr_accepted[RPC_ERRSTR_ACCEPTED_SIZE] = {
149         "",                     /* no good message... */
150         "remote server hasn't exported program.",
151         "remote server can't support version number.",
152         "program can't support procedure.",
153         "procedure can't decode params.",
154         "remote error.  remote side memory allocation failure?"
155 };
156
157 char *rpc_errstr_denied[2] = {
158         "remote server doesnt support rpc version 2!",
159         "remote server authentication error."
160 };
161
162 #define RPC_ERRSTR_AUTH_SIZE 6
163 char *rpc_errstr_auth[RPC_ERRSTR_AUTH_SIZE] = {
164         "",
165         "auth error: bad credential (seal broken).",
166         "auth error: client must begin new session.",
167         "auth error: bad verifier (seal broken).",
168         "auth error: verifier expired or replayed.",
169         "auth error: rejected for security reasons.",
170 };
171
172 /*
173  * Static data, mostly RPC constants in XDR form
174  */
175 static u_int32_t rpc_reply, rpc_call, rpc_vers;
176
177 /*
178  * rpc_msgdenied, rpc_mismatch, rpc_auth_unix, rpc_msgaccepted,
179  * rpc_autherr, rpc_auth_kerb;
180  */
181
182 static u_int32_t rpcclnt_xid = 0;
183 static u_int32_t rpcclnt_xid_touched = 0;
184 struct rpcstats rpcstats;
185 int      rpcclnt_ticks;
186
187 SYSCTL_NODE(_kern, OID_AUTO, rpc, CTLFLAG_RD, 0, "RPC Subsystem");
188
189 SYSCTL_UINT(_kern_rpc, OID_AUTO, retries, CTLFLAG_RD, &rpcstats.rpcretries, 0, "retries");
190 SYSCTL_UINT(_kern_rpc, OID_AUTO, request, CTLFLAG_RD, &rpcstats.rpcrequests, 0, "request");
191 SYSCTL_UINT(_kern_rpc, OID_AUTO, timeouts, CTLFLAG_RD, &rpcstats.rpctimeouts, 0, "timeouts");
192 SYSCTL_UINT(_kern_rpc, OID_AUTO, unexpected, CTLFLAG_RD, &rpcstats.rpcunexpected, 0, "unexpected");
193 SYSCTL_UINT(_kern_rpc, OID_AUTO, invalid, CTLFLAG_RD, &rpcstats.rpcinvalid, 0, "invalid");
194
195
196 #ifdef RPCCLNT_DEBUG
197 int             rpcdebugon = 0;
198 SYSCTL_UINT(_kern_rpc, OID_AUTO, debug_on, CTLFLAG_RW, &rpcdebugon, 0, "RPC Debug messages");
199 #endif
200
201 /*
202  * Queue head for rpctask's
203  */
204 static 
205 TAILQ_HEAD(, rpctask) rpctask_q;
206 struct callout  rpcclnt_callout;
207
208 #ifdef __OpenBSD__
209 static int             rpcclnt_send(struct socket *, struct mbuf *, struct mbuf *, struct rpctask *);
210 static int             rpcclnt_receive(struct rpctask *, struct mbuf **, struct mbuf **, RPC_EXEC_CTX);
211 #else
212 static int             rpcclnt_send(struct socket *, struct sockaddr *, struct mbuf *, struct rpctask *);
213 static int             rpcclnt_receive(struct rpctask *, struct sockaddr **, struct mbuf **, RPC_EXEC_CTX);
214 #endif
215
216 static int             rpcclnt_msg(RPC_EXEC_CTX, const char *, char *);
217
218 static int             rpcclnt_reply(struct rpctask *, RPC_EXEC_CTX);
219 static void            rpcclnt_timer(void *);
220 static int             rpcclnt_sndlock(int *, struct rpctask *);
221 static void            rpcclnt_sndunlock(int *);
222 static int             rpcclnt_rcvlock(struct rpctask *);
223 static void            rpcclnt_rcvunlock(int *);
224 #if 0
225 void            rpcclnt_realign(struct mbuf *, int);
226 #else
227 static void     rpcclnt_realign(struct mbuf **, int);
228 #endif
229
230 static struct mbuf    *rpcclnt_buildheader(struct rpcclnt *, int, struct mbuf *, u_int32_t, int *, struct mbuf **, struct ucred *);
231 static int             rpcm_disct(struct mbuf **, caddr_t *, int, int, caddr_t *);
232 static u_int32_t       rpcclnt_proct(struct rpcclnt *, u_int32_t);
233 static int             rpc_adv(struct mbuf **, caddr_t *, int, int);
234 static void     rpcclnt_softterm(struct rpctask * task);
235
236 static int rpcauth_buildheader(struct rpc_auth * auth, struct ucred *, struct mbuf **, caddr_t *);
237
238 void
239 rpcclnt_init(void)
240 {
241 #ifdef __OpenBSD__
242         static struct timeout rpcclnt_timer_to;
243 #endif
244
245         rpcclnt_ticks = (hz * RPC_TICKINTVL + 500) / 1000;
246         if (rpcclnt_ticks < 1)
247                 rpcclnt_ticks = 1;
248         rpcstats.rpcretries = 0;
249         rpcstats.rpcrequests = 0;
250         rpcstats.rpctimeouts = 0;
251         rpcstats.rpcunexpected = 0;
252         rpcstats.rpcinvalid = 0;
253
254         /*
255          * rpc constants how about actually using more than one of these!
256          */
257
258         rpc_reply = txdr_unsigned(RPC_REPLY);
259         rpc_vers = txdr_unsigned(RPC_VER2);
260         rpc_call = txdr_unsigned(RPC_CALL);
261 #if 0
262         rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
263         rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
264         rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
265         rpc_autherr = txdr_unsigned(RPC_AUTHERR);
266         rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
267         rpc_auth_kerb = txdr_unsigned(RPCAUTH_KERB4);
268 #endif
269
270         /* initialize rpctask queue */
271         TAILQ_INIT(&rpctask_q);
272
273 #ifdef __OpenBSD__
274         /* initialize pools */
275         pool_init(&rpctask_pool, sizeof(struct rpctask), 0, 0, RPCTASKPOOL_LWM,
276                   "rpctask_p", NULL);
277         pool_setlowat(&rpctask_pool, RPCTASKPOOL_LWM);
278         pool_sethiwat(&rpctask_pool, RPCTASKPOOL_HWM);
279
280         pool_init(&rpcclnt_pool, sizeof(struct rpcclnt), 0, 0, 1, "rpcclnt_p", NULL);
281
282         /* initialize timers */
283         timeout_set(&rpcclnt_timer_to, rpcclnt_timer, &rpcclnt_timer_to);
284         rpcclnt_timer(&rpcclnt_timer_to);
285 #else /* !__OpenBSD__ */
286         callout_init(&rpcclnt_callout, 0);
287 #endif /* !__OpenBSD__ */
288
289         RPCDEBUG("rpc initialed");
290
291         return;
292 }
293
294 void
295 rpcclnt_uninit(void)
296 {
297         RPCDEBUG("uninit");
298         /* XXX delete sysctl variables? */
299         callout_stop(&rpcclnt_callout);
300 }
301
302 int
303 rpcclnt_setup(clnt, program, addr, sotype, soproto, auth, max_read_size, max_write_size, flags)
304     struct rpcclnt * clnt;
305     struct rpc_program * program;
306     struct sockaddr * addr;
307     int sotype;
308     int soproto;
309     struct rpc_auth * auth;
310     int max_read_size;
311     int max_write_size;
312     int flags;
313 {
314         if (clnt == NULL || program == NULL || addr == NULL || auth == NULL)
315           RPC_RETURN (EFAULT);
316
317         if (program->prog_name == NULL)
318           RPC_RETURN (EFAULT);
319         clnt->rc_prog = program;
320
321         clnt->rc_name = addr;
322         clnt->rc_sotype = sotype;
323         clnt->rc_soproto = soproto;
324         clnt->rc_auth = auth;
325         clnt->rc_rsize = max_read_size;
326         clnt->rc_wsize = max_write_size;
327         clnt->rc_flag = flags;
328
329         clnt->rc_proctlen = 0;
330         clnt->rc_proct = NULL;
331
332         RPC_RETURN (0);
333 }
334
335 /*
336  * Initialize sockets and congestion for a new RPC connection. We do not free
337  * the sockaddr if error.
338  */
339 int
340 rpcclnt_connect(rpc, td)
341         struct rpcclnt *rpc;
342         RPC_EXEC_CTX td;
343 {
344         struct socket  *so;
345         int             s, error, rcvreserve, sndreserve;
346         struct sockaddr *saddr;
347
348 #ifdef __OpenBSD__
349         struct sockaddr_in *sin;
350         struct mbuf    *m;
351 #else
352         struct sockaddr_in sin;
353
354         int             soarg;
355         struct sockopt  opt;
356 #endif
357
358         if (rpc == NULL) {
359                 RPCDEBUG("no rpcclnt struct!\n");
360                 RPC_RETURN(EFAULT);
361         }
362
363         /* create the socket */
364         rpc->rc_so = NULL;
365
366         saddr = rpc->rc_name;
367
368         NET_LOCK_GIANT();
369         error = socreate(saddr->sa_family, &rpc->rc_so, rpc->rc_sotype,
370                          rpc->rc_soproto, td->td_ucred, td);
371         NET_UNLOCK_GIANT();
372
373         if (error) {
374                 RPCDEBUG("error %d in socreate()", error);
375                 RPC_RETURN(error);
376         }
377         so = rpc->rc_so;
378         rpc->rc_soflags = so->so_proto->pr_flags;
379
380         /*
381          * Some servers require that the client port be a reserved port
382          * number. We always allocate a reserved port, as this prevents
383          * filehandle disclosure through UDP port capture.
384          */
385         if (saddr->sa_family == AF_INET) {
386 #ifdef __OpenBSD__
387                 struct mbuf    *mopt;
388                 int            *ip;
389 #endif
390
391 #ifdef __OpenBSD__
392                 MGET(mopt, M_TRYWAIT, MT_SOOPTS);
393                 mopt->m_len = sizeof(int);
394                 ip = mtod(mopt, int *);
395                 *ip = IP_PORTRANGE_LOW;
396
397                 error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
398 #else
399                 soarg = IP_PORTRANGE_LOW;
400                 bzero(&opt, sizeof(struct sockopt));
401                 opt.sopt_dir = SOPT_SET;
402                 opt.sopt_level = IPPROTO_IP;
403                 opt.sopt_name = IP_PORTRANGE;
404                 opt.sopt_val = &soarg;
405                 opt.sopt_valsize = sizeof(soarg);
406
407                 error = sosetopt(so, &opt);
408 #endif
409                 if (error)
410                         goto bad;
411
412 #ifdef __OpenBSD__
413                 MGET(m, M_TRYWAIT, MT_SONAME);
414                 sin = mtod(m, struct sockaddr_in *);
415                 sin->sin_len = m->m_len = sizeof(struct sockaddr_in);
416                 sin->sin_family = AF_INET;
417                 sin->sin_addr.s_addr = INADDR_ANY;
418                 sin->sin_port = htons(0);
419                 error = sobind(so, m);
420                 m_freem(m);
421 #else
422                 sin.sin_len = sizeof(struct sockaddr_in);
423                 sin.sin_family = AF_INET;
424                 sin.sin_addr.s_addr = INADDR_ANY;
425                 sin.sin_port = htons(0);
426                 /*
427                  * &thread0 gives us root credentials to ensure sobind
428                  * will give us a reserved ephemeral port.
429                  */
430                 error = sobind(so, (struct sockaddr *) & sin, &thread0);
431 #endif
432                 if (error)
433                         goto bad;
434
435 #ifdef __OpenBSD__
436                 MGET(mopt, M_TRYWAIT, MT_SOOPTS);
437                 mopt->m_len = sizeof(int);
438                 ip = mtod(mopt, int *);
439                 *ip = IP_PORTRANGE_DEFAULT;
440                 error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
441 #else
442                 soarg = IP_PORTRANGE_DEFAULT;
443                 bzero(&opt, sizeof(struct sockopt));
444                 opt.sopt_dir = SOPT_SET;
445                 opt.sopt_level = IPPROTO_IP;
446                 opt.sopt_name = IP_PORTRANGE;
447                 opt.sopt_val = &soarg;
448                 opt.sopt_valsize = sizeof(soarg);
449                 error = sosetopt(so, &opt);
450 #endif
451                 if (error)
452                         goto bad;
453         }
454         /*
455          * Protocols that do not require connections may be optionally left
456          * unconnected for servers that reply from a port other than
457          * NFS_PORT.
458          */
459         if (rpc->rc_flag & RPCCLNT_NOCONN) {
460                 if (rpc->rc_soflags & PR_CONNREQUIRED) {
461                         error = ENOTCONN;
462                         goto bad;
463                 }
464         } else {
465                 error = soconnect(so, saddr, td);
466                 if (error)
467                         goto bad;
468
469                 /*
470                  * Wait for the connection to complete. Cribbed from the
471                  * connect system call but with the wait timing out so that
472                  * interruptible mounts don't hang here for a long time.
473                  */
474 #ifdef __OpenBSD__
475                 s = splsoftnet();
476 #else
477                 s = splnet();
478 #endif
479                 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
480                         (void)tsleep((caddr_t) & so->so_timeo, PSOCK,
481                                      "rpc", 2 * hz);
482
483                         /*
484                          * XXX needs to catch interrupt signals. something
485                          * like this: if ((so->so_state & SS_ISCONNECTING) &&
486                          * so->so_error == 0 && rep && (error =
487                          * nfs_sigintr(nmp, rep, rep->r_td)) != 0) {
488                          * so->so_state &= ~SS_ISCONNECTING; splx(s); goto
489                          * bad; }
490                          */
491                 }
492                 if (so->so_error) {
493                         error = so->so_error;
494                         so->so_error = 0;
495                         splx(s);
496                         goto bad;
497                 }
498                 splx(s);
499         }
500         if (rpc->rc_flag & (RPCCLNT_SOFT | RPCCLNT_INT)) {
501                 so->so_rcv.sb_timeo = (5 * hz);
502                 so->so_snd.sb_timeo = (5 * hz);
503         } else {
504                 so->so_rcv.sb_timeo = 0;
505                 so->so_snd.sb_timeo = 0;
506         }
507
508
509         if (rpc->rc_sotype == SOCK_DGRAM) {
510                 sndreserve = rpc->rc_wsize + RPC_MAXPKTHDR;
511                 rcvreserve = rpc->rc_rsize + RPC_MAXPKTHDR;
512         } else if (rpc->rc_sotype == SOCK_SEQPACKET) {
513                 sndreserve = (rpc->rc_wsize + RPC_MAXPKTHDR) * 2;
514                 rcvreserve = (rpc->rc_rsize + RPC_MAXPKTHDR) * 2;
515         } else {
516                 if (rpc->rc_sotype != SOCK_STREAM)
517                         panic("rpcclnt_connect() bad sotype");
518                 if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
519 #ifdef __OpenBSD__
520                         MGET(m, M_TRYWAIT, MT_SOOPTS);
521                         *mtod(m, int32_t *) = 1;
522                         m->m_len = sizeof(int32_t);
523                         sosetopt(so, SOL_SOCKET, SO_KEEPALIVE, m);
524 #else
525                         soarg = 1;
526
527                         bzero(&opt, sizeof(struct sockopt));
528                         opt.sopt_dir = SOPT_SET;
529                         opt.sopt_level = SOL_SOCKET;
530                         opt.sopt_name = SO_KEEPALIVE;
531                         opt.sopt_val = &soarg;
532                         opt.sopt_valsize = sizeof(soarg);
533                         sosetopt(so, &opt);
534 #endif
535                 }
536                 if (so->so_proto->pr_protocol == IPPROTO_TCP) {
537 #ifdef __OpenBSD__
538                         MGET(m, M_TRYWAIT, MT_SOOPTS);
539                         *mtod(m, int32_t *) = 1;
540                         m->m_len = sizeof(int32_t);
541                         sosetopt(so, IPPROTO_TCP, TCP_NODELAY, m);
542 #else
543                         soarg = 1;
544
545                         bzero(&opt, sizeof(struct sockopt));
546                         opt.sopt_dir = SOPT_SET;
547                         opt.sopt_level = IPPROTO_TCP;
548                         opt.sopt_name = TCP_NODELAY;
549                         opt.sopt_val = &soarg;
550                         opt.sopt_valsize = sizeof(soarg);
551                         sosetopt(so, &opt);
552 #endif
553                 }
554                 sndreserve = (rpc->rc_wsize + RPC_MAXPKTHDR +
555                               sizeof(u_int32_t)) * 2;
556                 rcvreserve = (rpc->rc_rsize + RPC_MAXPKTHDR +
557                               sizeof(u_int32_t)) * 2;
558         }
559         error = soreserve(so, sndreserve, rcvreserve);
560         if (error)
561                 goto bad;
562         so->so_rcv.sb_flags |= SB_NOINTR;
563         so->so_snd.sb_flags |= SB_NOINTR;
564
565         /* Initialize other non-zero congestion variables */
566         rpc->rc_srtt[0] = rpc->rc_srtt[1] = rpc->rc_srtt[2] =
567                  rpc->rc_srtt[3] = (RPC_TIMEO << 3);
568         rpc->rc_sdrtt[0] = rpc->rc_sdrtt[1] = rpc->rc_sdrtt[2] =
569                 rpc->rc_sdrtt[3] = 0;
570         rpc->rc_cwnd = RPC_MAXCWND / 2; /* Initial send window */
571         rpc->rc_sent = 0;
572         rpc->rc_timeouts = 0;
573         RPC_RETURN(0);
574
575 bad:
576         rpcclnt_disconnect(rpc);
577         RPC_RETURN(error);
578 }
579
580
581 /*
582  * Reconnect routine:
583  * Called when a connection is broken on a reliable protocol.
584  * - clean up the old socket
585  * - rpcclnt_connect() again
586  * - set R_MUSTRESEND for all outstanding requests on mount point
587  * If this fails the mount point is DEAD!
588  * nb: Must be called with the rpcclnt_sndlock() set on the mount point.
589  */
590 int
591 rpcclnt_reconnect(rep, td)
592         struct rpctask *rep;
593         RPC_EXEC_CTX td;
594 {
595         struct rpctask *rp;
596         struct rpcclnt *rpc = rep->r_rpcclnt;
597         int             error;
598
599         rpcclnt_disconnect(rpc);
600         while ((error = rpcclnt_connect(rpc, td)) != 0) {
601                 if (error == EINTR || error == ERESTART)
602                         RPC_RETURN(EINTR);
603                 tsleep(&lbolt, PSOCK, "rpccon", 0);
604         }
605
606         /*
607          * Loop through outstanding request list and fix up all requests on
608          * old socket.
609          */
610         for (rp = TAILQ_FIRST(&rpctask_q); rp != NULL;
611              rp = TAILQ_NEXT(rp, r_chain)) {
612                 if (rp->r_rpcclnt == rpc)
613                         rp->r_flags |= R_MUSTRESEND;
614         }
615         RPC_RETURN(0);
616 }
617
618 /*
619  * RPC transport disconnect. Clean up and unlink.
620  */
621 void
622 rpcclnt_disconnect(rpc)
623         struct rpcclnt *rpc;
624 {
625         struct socket  *so;
626
627         if (rpc->rc_so) {
628                 so = rpc->rc_so;
629                 rpc->rc_so = NULL;
630                 NET_LOCK_GIANT();
631                 soshutdown(so, 2);
632                 soclose(so);
633                 NET_UNLOCK_GIANT();
634         }
635 }
636
637 void
638 rpcclnt_safedisconnect(struct rpcclnt * rpc)
639 {
640         struct rpctask  dummytask;
641
642         bzero(&dummytask, sizeof(dummytask));
643         dummytask.r_rpcclnt = rpc;
644         rpcclnt_rcvlock(&dummytask);
645         rpcclnt_disconnect(rpc);
646         rpcclnt_rcvunlock(&rpc->rc_flag);
647 }
648
649 /*
650  * This is the rpc send routine. For connection based socket types, it
651  * must be called with an rpcclnt_sndlock() on the socket.
652  * "rep == NULL" indicates that it has been called from a server.
653  * For the client side:
654  * - return EINTR if the RPC is terminated, 0 otherwise
655  * - set R_MUSTRESEND if the send fails for any reason
656  * - do any cleanup required by recoverable socket errors (?)
657  * For the server side:
658  * - return EINTR or ERESTART if interrupted by a signal
659  * - return EPIPE if a connection is lost for connection based sockets (TCP...)
660  * - do any cleanup required by recoverable socket errors (?)
661  */
662 static int
663 rpcclnt_send(so, nam, top, rep)
664         struct socket  *so;
665 #ifdef __OpenBSD__
666         struct mbuf    *nam;
667 #else
668         struct sockaddr *nam;
669 #endif
670         struct mbuf    *top;
671         struct rpctask *rep;
672 {
673 #ifdef __OpenBSD__
674         struct mbuf    *sendnam;
675 #else
676         struct sockaddr *sendnam;
677         struct thread  *td = curthread;
678 #endif
679         int error, soflags, flags;
680
681         if (rep) {
682                 if (rep->r_flags & R_SOFTTERM) {
683                         m_freem(top);
684                         RPC_RETURN(EINTR);
685                 }
686                 if ((so = rep->r_rpcclnt->rc_so) == NULL) {
687                         rep->r_flags |= R_MUSTRESEND;
688                         m_freem(top);
689                         RPC_RETURN(0);
690                 }
691                 rep->r_flags &= ~R_MUSTRESEND;
692                 soflags = rep->r_rpcclnt->rc_soflags;
693         } else
694                 soflags = so->so_proto->pr_flags;
695
696         if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED))
697                 sendnam = NULL;
698         else
699                 sendnam = nam;
700
701         if (so->so_type == SOCK_SEQPACKET)
702                 flags = MSG_EOR;
703         else
704                 flags = 0;
705
706         /*
707          * XXXRW: If/when this code becomes MPSAFE itself, Giant might have
708          * to be conditionally acquired earlier for the stack so has to avoid
709          * lock order reversals with any locks held over rpcclnt_send().
710          */
711         NET_LOCK_GIANT();
712         error = sosend(so, sendnam, NULL, top, NULL, flags, td);
713         NET_UNLOCK_GIANT();
714
715         if (error) {
716                 if (rep) {
717                         log(LOG_INFO, "rpc send error %d for service %s\n", error,
718                             rep->r_rpcclnt->rc_prog->prog_name);
719                         /*
720                          * Deal with errors for the client side.
721                          */
722                         if (rep->r_flags & R_SOFTTERM)
723                                 error = EINTR;
724                         else
725                                 rep->r_flags |= R_MUSTRESEND;
726                 } else
727                         log(LOG_INFO, "rpc service send error %d\n", error);
728
729                 /*
730                  * Handle any recoverable (soft) socket errors here.
731                  */
732                 if (error != EINTR && error != ERESTART &&
733                     error != EWOULDBLOCK && error != EPIPE)
734                         error = 0;
735         }
736         RPC_RETURN(error);
737 }
738
739 /*
740  * Receive a Sun RPC Request/Reply. For SOCK_DGRAM, the work is all done by
741  * soreceive(), but for SOCK_STREAM we must deal with the Record Mark and
742  * consolidate the data into a new mbuf list. nb: Sometimes TCP passes the
743  * data up to soreceive() in long lists of small mbufs. For SOCK_STREAM we
744  * must be very careful to read an entire record once we have read any of it,
745  * even if the system call has been interrupted.
746  */
747 static int
748 rpcclnt_receive(rep, aname, mp, td)
749         struct rpctask *rep;
750 #ifdef __OpenBSD__
751         struct mbuf   **aname;
752 #else
753         struct sockaddr **aname;
754 #endif
755         struct mbuf   **mp;
756         RPC_EXEC_CTX  td;
757 {
758         struct socket  *so;
759         struct uio      auio;
760         struct iovec    aio;
761         struct mbuf    *m;
762         struct mbuf    *control;
763         u_int32_t       len;
764 #ifdef __OpenBSD__
765         struct mbuf   **getnam;
766 #else
767         struct sockaddr **getnam;
768 #endif
769         int error, sotype, rcvflg;
770
771         /*
772          * Set up arguments for soreceive()
773          */
774         *mp = NULL;
775         *aname = NULL;
776         sotype = rep->r_rpcclnt->rc_sotype;
777
778         /*
779          * For reliable protocols, lock against other senders/receivers in
780          * case a reconnect is necessary. For SOCK_STREAM, first get the
781          * Record Mark to find out how much more there is to get. We must
782          * lock the socket against other receivers until we have an entire
783          * rpc request/reply.
784          */
785         if (sotype != SOCK_DGRAM) {
786                 error = rpcclnt_sndlock(&rep->r_rpcclnt->rc_flag, rep);
787                 if (error)
788                         RPC_RETURN(error);
789 tryagain:
790                 /*
791                  * Check for fatal errors and resending request.
792                  */
793                 /*
794                  * Ugh: If a reconnect attempt just happened, rc_so would
795                  * have changed. NULL indicates a failed attempt that has
796                  * essentially shut down this mount point.
797                  */
798                 if (rep->r_mrep || (rep->r_flags & R_SOFTTERM)) {
799                         rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
800                         RPC_RETURN(EINTR);
801                 }
802                 so = rep->r_rpcclnt->rc_so;
803                 if (!so) {
804                         error = rpcclnt_reconnect(rep, td);
805                         if (error) {
806                                 rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
807                                 RPC_RETURN(error);
808                         }
809                         goto tryagain;
810                 }
811                 while (rep->r_flags & R_MUSTRESEND) {
812                         m = m_copym(rep->r_mreq, 0, M_COPYALL, M_TRYWAIT);
813                         rpcstats.rpcretries++;
814                         error = rpcclnt_send(so, rep->r_rpcclnt->rc_name, m, rep);
815                         if (error) {
816                                 if (error == EINTR || error == ERESTART ||
817                                     (error = rpcclnt_reconnect(rep, td)) != 0) {
818                                         rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
819                                         RPC_RETURN(error);
820                                 }
821                                 goto tryagain;
822                         }
823                 }
824                 rpcclnt_sndunlock(&rep->r_rpcclnt->rc_flag);
825                 if (sotype == SOCK_STREAM) {
826                         aio.iov_base = (caddr_t) & len;
827                         aio.iov_len = sizeof(u_int32_t);
828                         auio.uio_iov = &aio;
829                         auio.uio_iovcnt = 1;
830                         auio.uio_segflg = UIO_SYSSPACE;
831                         auio.uio_rw = UIO_READ;
832                         auio.uio_offset = 0;
833                         auio.uio_resid = sizeof(u_int32_t);
834 #ifdef __OpenBSD__
835                         auio.uio_procp = td;
836 #else
837                         auio.uio_td = td;
838 #endif
839                         do {
840                                 rcvflg = MSG_WAITALL;
841                                 NET_LOCK_GIANT();
842                                 error = soreceive(so, NULL, &auio, NULL, NULL, &rcvflg);
843                                 NET_UNLOCK_GIANT();
844                                 if (error == EWOULDBLOCK && rep) {
845                                         if (rep->r_flags & R_SOFTTERM)
846                                                 RPC_RETURN(EINTR);
847                                 }
848                         } while (error == EWOULDBLOCK);
849                         if (!error && auio.uio_resid > 0) {
850                                 log(LOG_INFO,
851                                 "short receive (%zu/%zu) from rpc server %s\n",
852                                     sizeof(u_int32_t) - auio.uio_resid,
853                                     sizeof(u_int32_t),
854                                     rep->r_rpcclnt->rc_prog->prog_name);
855                                 error = EPIPE;
856                         }
857                         if (error)
858                                 goto errout;
859                         len = ntohl(len) & ~0x80000000;
860                         /*
861                          * This is SERIOUS! We are out of sync with the
862                          * sender and forcing a disconnect/reconnect is all I
863                          * can do.
864                          */
865                         if (len > RPC_MAXPACKET) {
866                                 log(LOG_ERR, "%s (%d) from rpc server %s\n",
867                                     "impossible packet length",
868                                     len,
869                                     rep->r_rpcclnt->rc_prog->prog_name);
870                                 error = EFBIG;
871                                 goto errout;
872                         }
873                         auio.uio_resid = len;
874                         do {
875                                 rcvflg = MSG_WAITALL;
876                                 NET_LOCK_GIANT();
877                                 error = soreceive(so, NULL, &auio, mp, NULL, &rcvflg);
878                                 NET_UNLOCK_GIANT();
879                         } while (error == EWOULDBLOCK || error == EINTR ||
880                                  error == ERESTART);
881                         if (!error && auio.uio_resid > 0) {
882                                 log(LOG_INFO,
883                                 "short receive (%d/%d) from rpc server %s\n",
884                                     len - auio.uio_resid, len,
885                                     rep->r_rpcclnt->rc_prog->prog_name);
886                                 error = EPIPE;
887                         }
888                 } else {
889                         /*
890                          * NB: Since uio_resid is big, MSG_WAITALL is ignored
891                          * and soreceive() will return when it has either a
892                          * control msg or a data msg. We have no use for
893                          * control msg., but must grab them and then throw
894                          * them away so we know what is going on.
895                          */
896                         auio.uio_resid = len = 100000000;       /* Anything Big */
897 #ifdef __OpenBSD__
898                         auio.uio_procp = td;
899 #else
900                         auio.uio_td = td;
901 #endif
902                         do {
903                                 rcvflg = 0;
904                                 NET_LOCK_GIANT();
905                                 error = soreceive(so, NULL, &auio, mp, &control, &rcvflg);
906                                 NET_UNLOCK_GIANT();
907                                 if (control)
908                                         m_freem(control);
909                                 if (error == EWOULDBLOCK && rep) {
910                                         if (rep->r_flags & R_SOFTTERM)
911                                                 RPC_RETURN(EINTR);
912                                 }
913                         } while (error == EWOULDBLOCK ||
914                                  (!error && *mp == NULL && control));
915                         if ((rcvflg & MSG_EOR) == 0)
916                                 printf("Egad!!\n");
917                         if (!error && *mp == NULL)
918                                 error = EPIPE;
919                         len -= auio.uio_resid;
920                 }
921 errout:
922                 if (error && error != EINTR && error != ERESTART) {
923                         m_freem(*mp);
924                         *mp = (struct mbuf *) 0;
925                         if (error != EPIPE)
926                                 log(LOG_INFO,
927                                     "receive error %d from rpc server %s\n",
928                                     error,
929                                     rep->r_rpcclnt->rc_prog->prog_name);
930                         error = rpcclnt_sndlock(&rep->r_rpcclnt->rc_flag, rep);
931                         if (!error)
932                                 error = rpcclnt_reconnect(rep, td);
933                         if (!error)
934                                 goto tryagain;
935                 }
936         } else {
937                 if ((so = rep->r_rpcclnt->rc_so) == NULL)
938                         RPC_RETURN(EACCES);
939                 if (so->so_state & SS_ISCONNECTED)
940                         getnam = NULL;
941                 else
942                         getnam = aname;
943                 auio.uio_resid = len = 1000000;
944 #ifdef __OpenBSD__
945                 auio.uio_procp = td;
946 #else
947                 auio.uio_td = td;
948 #endif
949
950                 do {
951                         rcvflg = 0;
952                         NET_LOCK_GIANT();
953                         error = soreceive(so, getnam, &auio, mp, NULL, &rcvflg);
954                         NET_UNLOCK_GIANT();
955                         RPCDEBUG("soreceive returns %d", error);
956                         if (error == EWOULDBLOCK && (rep->r_flags & R_SOFTTERM)) {
957                                 RPCDEBUG("wouldblock && softerm -> EINTR");
958                                 RPC_RETURN(EINTR);
959                         }
960                 } while (error == EWOULDBLOCK);
961                 len -= auio.uio_resid;
962         }
963         if (error) {
964                 m_freem(*mp);
965                 *mp = NULL;
966         } else {
967                 /*
968                  * Search for any mbufs that are not a multiple of 4 bytes
969                  * long or with m_data not longword aligned. These could
970                  * cause pointer alignment problems, so copy them to well
971                  * aligned mbufs.
972                  */
973                 rpcclnt_realign(mp, 5 * RPCX_UNSIGNED);
974         }
975         RPC_RETURN(error);
976 }
977
978
979 /*
980  * Implement receipt of reply on a socket. We must search through the list of
981  * received datagrams matching them with outstanding requests using the xid,
982  * until ours is found.
983  */
984 /* ARGSUSED */
985 static int
986 rpcclnt_reply(myrep, td)
987         struct rpctask *myrep;
988         RPC_EXEC_CTX td;
989 {
990         struct rpctask *rep;
991         struct rpcclnt *rpc = myrep->r_rpcclnt;
992         int32_t         t1;
993         struct mbuf    *mrep, *md;
994 #ifdef __OpenBSD__
995         struct mbuf    *nam;
996 #else
997         struct sockaddr *nam;
998 #endif
999         u_int32_t       rxid, *tl;
1000         caddr_t         dpos, cp2;
1001         int             error;
1002
1003         /*
1004          * Loop around until we get our own reply
1005          */
1006         for (;;) {
1007                 /*
1008                  * Lock against other receivers so that I don't get stuck in
1009                  * sbwait() after someone else has received my reply for me.
1010                  * Also necessary for connection based protocols to avoid
1011                  * race conditions during a reconnect.
1012                  */
1013                 error = rpcclnt_rcvlock(myrep);
1014                 if (error)
1015                         RPC_RETURN(error);
1016                 /* Already received, bye bye */
1017                 if (myrep->r_mrep != NULL) {
1018                         rpcclnt_rcvunlock(&rpc->rc_flag);
1019                         RPC_RETURN(0);
1020                 }
1021                 /*
1022                  * Get the next Rpc reply off the socket
1023                  */
1024                 error = rpcclnt_receive(myrep, &nam, &mrep, td);
1025
1026                 rpcclnt_rcvunlock(&rpc->rc_flag);
1027
1028                 if (error) {
1029                         /*
1030                          * Ignore routing errors on connectionless
1031                          * protocols??
1032                          */
1033                         if (RPCIGNORE_SOERROR(rpc->rc_soflags, error)) {
1034                                 rpc->rc_so->so_error = 0;
1035                                 if (myrep->r_flags & R_GETONEREP)
1036                                         RPC_RETURN(0);
1037                                 RPCDEBUG("ingoring routing error on connectionless protocol.");
1038                                 continue;
1039                         }
1040                         RPC_RETURN(error);
1041                 }
1042 #ifdef __OpenBSD__
1043                 if (nam)
1044                         m_freem(nam);
1045 #else
1046                 if (nam)
1047                         FREE(nam, M_SONAME);
1048 #endif
1049
1050                 /*
1051                  * Get the xid and check that it is an rpc reply
1052                  */
1053                 md = mrep;
1054                 dpos = mtod(md, caddr_t);
1055                 rpcm_dissect(tl, u_int32_t *, 2 * RPCX_UNSIGNED);
1056                 rxid = *tl++;
1057                 if (*tl != rpc_reply) {
1058                         rpcstats.rpcinvalid++;
1059                         m_freem(mrep);
1060 rpcmout:
1061                         if (myrep->r_flags & R_GETONEREP)
1062                                 RPC_RETURN(0);
1063                         continue;
1064                 }
1065                 /*
1066                  * Loop through the request list to match up the reply Iff no
1067                  * match, just drop the datagram
1068                  */
1069                 TAILQ_FOREACH(rep, &rpctask_q, r_chain) {
1070                         if (rep->r_mrep == NULL && rxid == rep->r_xid) {
1071                                 /* Found it.. */
1072                                 rep->r_mrep = mrep;
1073                                 rep->r_md = md;
1074                                 rep->r_dpos = dpos;
1075
1076                                 /*
1077                                  * Update congestion window. Do the additive
1078                                  * increase of one rpc/rtt.
1079                                  */
1080                                 if (rpc->rc_cwnd <= rpc->rc_sent) {
1081                                         rpc->rc_cwnd +=
1082                                                 (RPC_CWNDSCALE * RPC_CWNDSCALE +
1083                                         (rpc->rc_cwnd >> 1)) / rpc->rc_cwnd;
1084                                         if (rpc->rc_cwnd > RPC_MAXCWND)
1085                                                 rpc->rc_cwnd = RPC_MAXCWND;
1086                                 }
1087                                 rep->r_flags &= ~R_SENT;
1088                                 rpc->rc_sent -= RPC_CWNDSCALE;
1089                                 /*
1090                                  * Update rtt using a gain of 0.125 on the
1091                                  * mean and a gain of 0.25 on the deviation.
1092                                  */
1093                                 if (rep->r_flags & R_TIMING) {
1094                                         /*
1095                                          * Since the timer resolution of
1096                                          * NFS_HZ is so course, it can often
1097                                          * result in r_rtt == 0. Since r_rtt
1098                                          * == N means that the actual rtt is
1099                                          * between N+dt and N+2-dt ticks, add
1100                                          * 1.
1101                                          */
1102                                         t1 = rep->r_rtt + 1;
1103                                         t1 -= (RPC_SRTT(rpc, rep) >> 3);
1104                                         RPC_SRTT(rpc, rep) += t1;
1105                                         if (t1 < 0)
1106                                                 t1 = -t1;
1107                                         t1 -= (RPC_SDRTT(rpc, rep) >> 2);
1108                                         RPC_SDRTT(rpc, rep) += t1;
1109                                 }
1110                                 rpc->rc_timeouts = 0;
1111                                 break;
1112                         }
1113                 }
1114                 /*
1115                  * If not matched to a request, drop it. If it's mine, get
1116                  * out.
1117                  */
1118                 if (rep == 0) {
1119                         rpcstats.rpcunexpected++;
1120                         RPCDEBUG("rpc reply not matched\n");
1121                         m_freem(mrep);
1122                 } else if (rep == myrep) {
1123                         if (rep->r_mrep == NULL)
1124                                 panic("rpcreply nil");
1125                         RPC_RETURN(0);
1126                 }
1127                 if (myrep->r_flags & R_GETONEREP)
1128                         RPC_RETURN(0);
1129         }
1130 }
1131
1132 /* XXX: ignores tryagain! */
1133 /*
1134  * code from nfs_request - goes something like this
1135  *      - fill in task struct
1136  *      - links task into list
1137  *      - calls rpcclnt_send() for first transmit
1138  *      - calls rpcclnt_reply() to get reply
1139  *      - fills in reply (which should be initialized prior to
1140  *        calling), which is valid when 0 is returned and is
1141  *        NEVER freed in this function
1142  * 
1143  * nb: always frees the request header, but NEVER frees 'mrest'
1144  * 
1145  * rpcclnt_setauth() should be used before calling this. EAUTH is returned if
1146  * authentication fails.
1147  *
1148  * note that reply->result_* are invalid unless reply->type ==
1149  * RPC_MSGACCEPTED and reply->status == RPC_SUCCESS and that reply->verf_*
1150  * are invalid unless reply->type == RPC_MSGACCEPTED
1151  */
1152 int
1153 rpcclnt_request(rpc, mrest, procnum, td, cred, reply)
1154         struct rpcclnt *rpc;
1155         struct mbuf    *mrest;
1156         int             procnum;
1157         RPC_EXEC_CTX    td;
1158         struct ucred   *cred;
1159         struct rpc_reply *reply;
1160 {
1161         struct mbuf    *m, *mrep;
1162         struct rpctask *task;
1163         u_int32_t      *tl;
1164         struct mbuf    *md, *mheadend;
1165         caddr_t         dpos, cp2;
1166         int             t1, s, error = 0, mrest_len;
1167         u_int32_t       xid;
1168
1169 #ifdef __OpenBSD__
1170         task = pool_get(&rpctask_pool, PR_WAITOK);
1171 #else
1172         MALLOC(task, struct rpctask *, sizeof(struct rpctask), M_RPC, (M_WAITOK | M_ZERO));
1173 #endif
1174
1175         task->r_rpcclnt = rpc;
1176         task->r_procnum = procnum;
1177         task->r_td = td;
1178
1179         mrest_len = m_length(mrest, NULL);
1180
1181         m = rpcclnt_buildheader(rpc, procnum, mrest, mrest_len, &xid, &mheadend,
1182             cred);
1183
1184         /*
1185          * For stream protocols, insert a Sun RPC Record Mark.
1186          */
1187         if (rpc->rc_sotype == SOCK_STREAM) {
1188                 M_PREPEND(m, RPCX_UNSIGNED, M_TRYWAIT);
1189                 *mtod(m, u_int32_t *) = htonl(0x80000000 |
1190                                          (m->m_pkthdr.len - RPCX_UNSIGNED));
1191         }
1192         task->r_mreq = m;
1193         task->r_xid = xid;
1194
1195         if (rpc->rc_flag & RPCCLNT_SOFT)
1196                 task->r_retry = rpc->rc_retry;
1197         else
1198                 task->r_retry = RPC_MAXREXMIT + 1;      /* past clip limit */
1199         task->r_rtt = task->r_rexmit = 0;
1200
1201         if (rpcclnt_proct(rpc, procnum) > 0)
1202                 task->r_flags = R_TIMING;
1203         else
1204                 task->r_flags = 0;
1205         task->r_mrep = NULL;
1206
1207         /*
1208          * Do the client side RPC.
1209          */
1210         rpcstats.rpcrequests++;
1211
1212         /*
1213          * Chain request into list of outstanding requests. Be sure to put it
1214          * LAST so timer finds oldest requests first.
1215          */
1216         s = splsoftclock();
1217         if (TAILQ_EMPTY(&rpctask_q))
1218                 callout_reset(&rpcclnt_callout, rpcclnt_ticks, rpcclnt_timer,
1219                     NULL);
1220         TAILQ_INSERT_TAIL(&rpctask_q, task, r_chain);
1221
1222         /*
1223          * If backing off another request or avoiding congestion, don't send
1224          * this one now but let timer do it. If not timing a request, do it
1225          * now.
1226          */
1227         if (rpc->rc_so && (rpc->rc_sotype != SOCK_DGRAM ||
1228                            (rpc->rc_flag & RPCCLNT_DUMBTIMR) ||
1229                            rpc->rc_sent < rpc->rc_cwnd)) {
1230                 splx(s);
1231
1232                 if (rpc->rc_soflags & PR_CONNREQUIRED)
1233                         error = rpcclnt_sndlock(&rpc->rc_flag, task);
1234                 if (!error) {
1235                         error = rpcclnt_send(rpc->rc_so, rpc->rc_name,
1236                                              m_copym(m, 0, M_COPYALL, M_TRYWAIT),
1237                                              task);
1238                         if (rpc->rc_soflags & PR_CONNREQUIRED)
1239                                 rpcclnt_sndunlock(&rpc->rc_flag);
1240                 }
1241                 if (!error && (task->r_flags & R_MUSTRESEND) == 0) {
1242                         rpc->rc_sent += RPC_CWNDSCALE;
1243                         task->r_flags |= R_SENT;
1244                 }
1245         } else {
1246                 splx(s);
1247                 task->r_rtt = -1;
1248         }
1249
1250         /*
1251          * Wait for the reply from our send or the timer's.
1252          */
1253         if (!error || error == EPIPE)
1254                 error = rpcclnt_reply(task, td);
1255
1256         /*
1257          * RPC done, unlink the request.
1258          */
1259         s = splsoftclock();
1260         TAILQ_REMOVE(&rpctask_q, task, r_chain);
1261         if (TAILQ_EMPTY(&rpctask_q))
1262                 callout_stop(&rpcclnt_callout);
1263         splx(s);
1264
1265         /*
1266          * Decrement the outstanding request count.
1267          */
1268         if (task->r_flags & R_SENT) {
1269                 task->r_flags &= ~R_SENT;       /* paranoia */
1270                 rpc->rc_sent -= RPC_CWNDSCALE;
1271         }
1272         /*
1273          * If there was a successful reply and a tprintf msg. tprintf a
1274          * response.
1275          */
1276         if (!error && (task->r_flags & R_TPRINTFMSG)) {
1277                 mtx_lock(&Giant);
1278                 rpcclnt_msg(task->r_td, rpc->rc_prog->prog_name,
1279                             "is alive again");
1280                 mtx_unlock(&Giant);
1281         }
1282
1283         /* free request header (leaving mrest) */
1284         mheadend->m_next = NULL;
1285         m_freem(task->r_mreq);
1286
1287         /* initialize reply */
1288         reply->mrep = task->r_mrep;
1289         reply->verf_md = NULL;
1290         reply->result_md = NULL;
1291
1292         mrep = task->r_mrep;
1293         md = task->r_md;
1294         dpos = task->r_dpos;
1295
1296         /* task structure is no longer needed */
1297 #ifdef __OpenBSD__
1298         pool_put(&rpctask_pool, task);
1299 #else
1300         FREE(task, M_RPC);
1301 #endif
1302
1303         if (error)
1304                 goto rpcmout;
1305
1306         /*
1307          * break down the rpc header and check if ok
1308          */
1309
1310         rpcm_dissect(tl, u_int32_t *, RPCX_UNSIGNED);
1311         reply->stat.type = fxdr_unsigned(u_int32_t, *tl);
1312
1313         if (reply->stat.type == RPC_MSGDENIED) {
1314                 rpcm_dissect(tl, u_int32_t *, RPCX_UNSIGNED);
1315                 reply->stat.status = fxdr_unsigned(u_int32_t, *tl);
1316
1317                 switch (reply->stat.status) {
1318                 case RPC_MISMATCH:
1319                         rpcm_dissect(tl, u_int32_t *, 2 * RPCX_UNSIGNED);
1320                         reply->stat.mismatch_info.low = fxdr_unsigned(u_int32_t, *tl++);
1321                         reply->stat.mismatch_info.high = fxdr_unsigned(u_int32_t, *tl);
1322                         error = EOPNOTSUPP;
1323                         break;
1324                 case RPC_AUTHERR:
1325                         rpcm_dissect(tl, u_int32_t *, RPCX_UNSIGNED);
1326                         reply->stat.autherr = fxdr_unsigned(u_int32_t, *tl);
1327                         error = EACCES;
1328                         break;
1329                 default:
1330                         error = EBADRPC;
1331                         break;
1332                 }
1333                 goto rpcmout;
1334         } else if (reply->stat.type != RPC_MSGACCEPTED) {
1335                 error = EBADRPC;
1336                 goto rpcmout;
1337         }
1338
1339         rpcm_dissect(tl, u_int32_t *, 2 * RPCX_UNSIGNED);
1340
1341         reply->verf_md = md;
1342         reply->verf_dpos = dpos;
1343
1344         reply->verf_type = fxdr_unsigned(u_int32_t, *tl++);
1345         reply->verf_size = fxdr_unsigned(u_int32_t, *tl);
1346
1347         if (reply->verf_size != 0)
1348                 rpcm_adv(rpcm_rndup(reply->verf_size));
1349
1350         rpcm_dissect(tl, u_int32_t *, RPCX_UNSIGNED);
1351         reply->stat.status = fxdr_unsigned(u_int32_t, *tl);
1352
1353         if (reply->stat.status == RPC_SUCCESS) {
1354                 if ((uint32_t)(dpos - mtod(md, caddr_t)) >= md->m_len) {
1355                         RPCDEBUG("where is the next mbuf?");
1356                         RPCDEBUG("%d -> %d",
1357                             (int)(dpos - mtod(md, caddr_t)), md->m_len);
1358                         if (md->m_next == NULL) {
1359                                 error = EBADRPC;
1360                                 goto rpcmout;
1361                         } else {
1362                                 reply->result_md = md->m_next;
1363                                 reply->result_dpos = mtod(reply->result_md,
1364                                     caddr_t);
1365                         }
1366                 } else {
1367                         reply->result_md = md;
1368                         reply->result_dpos = dpos;
1369                 }
1370         } else if (reply->stat.status == RPC_PROGMISMATCH) {
1371                 rpcm_dissect(tl, u_int32_t *, 2 * RPCX_UNSIGNED);
1372                 reply->stat.mismatch_info.low = fxdr_unsigned(u_int32_t, *tl++);
1373                 reply->stat.mismatch_info.high = fxdr_unsigned(u_int32_t, *tl);
1374                 error = EOPNOTSUPP;
1375                 goto rpcmout;
1376         } else {
1377                 error = EPROTONOSUPPORT;
1378                 goto rpcmout;
1379         }
1380         error = 0;
1381
1382 rpcmout:
1383         RPC_RETURN(error);
1384 }
1385
1386
1387 /*
1388  * RPC timer routine
1389  * Scan the rpctask list and retranmit any requests that have timed out.
1390  * To avoid retransmission attempts on STREAM sockets (in the future) make
1391  * sure to set the r_retry field to 0 (implies nm_retry == 0).
1392  */
1393 void
1394 rpcclnt_timer(arg)
1395         void           *arg;
1396 {
1397 #ifdef __OpenBSD__
1398         struct timeout *to = (struct timeout *) arg;
1399 #endif
1400         struct rpctask *rep;
1401         struct mbuf    *m;
1402         struct socket  *so;
1403         struct rpcclnt *rpc;
1404         int             timeo;
1405         int             s, error;
1406
1407 #ifndef __OpenBSD__
1408         struct thread  *td = curthread;
1409 #endif
1410
1411 #ifdef __OpenBSD__
1412         s = splsoftnet();
1413 #else
1414         s = splnet();
1415 #endif
1416         mtx_lock(&Giant);       /* rpc_msg -> tprintf */
1417         TAILQ_FOREACH(rep, &rpctask_q, r_chain) {
1418                 rpc = rep->r_rpcclnt;
1419                 if (rep->r_mrep || (rep->r_flags & R_SOFTTERM))
1420                         continue;
1421                 if (rpcclnt_sigintr(rpc, rep, rep->r_td)) {
1422                         rep->r_flags |= R_SOFTTERM;
1423                         continue;
1424                 }
1425                 if (rep->r_rtt >= 0) {
1426                         rep->r_rtt++;
1427                         if (rpc->rc_flag & RPCCLNT_DUMBTIMR)
1428                                 timeo = rpc->rc_timeo;
1429                         else
1430                                 timeo = RPC_RTO(rpc, rpcclnt_proct(rep->r_rpcclnt,
1431                                                            rep->r_procnum));
1432                         if (rpc->rc_timeouts > 0)
1433                                 timeo *= rpcclnt_backoff[rpc->rc_timeouts - 1];
1434                         if (rep->r_rtt <= timeo)
1435                                 continue;
1436                         if (rpc->rc_timeouts < 8)
1437                                 rpc->rc_timeouts++;
1438                 }
1439                 /*
1440                  * Check for server not responding
1441                  */
1442                 if ((rep->r_flags & R_TPRINTFMSG) == 0 &&
1443                     rep->r_rexmit > rpc->rc_deadthresh) {
1444                         rpcclnt_msg(rep->r_td, rpc->rc_prog->prog_name,
1445                                     "not responding");
1446                         rep->r_flags |= R_TPRINTFMSG;
1447                 }
1448                 if (rep->r_rexmit >= rep->r_retry) {    /* too many */
1449                         rpcstats.rpctimeouts++;
1450                         rep->r_flags |= R_SOFTTERM;
1451                         continue;
1452                 }
1453                 if (rpc->rc_sotype != SOCK_DGRAM) {
1454                         if (++rep->r_rexmit > RPC_MAXREXMIT)
1455                                 rep->r_rexmit = RPC_MAXREXMIT;
1456                         continue;
1457                 }
1458                 if ((so = rpc->rc_so) == NULL)
1459                         continue;
1460
1461                 /*
1462                  * If there is enough space and the window allows.. Resend it
1463                  * Set r_rtt to -1 in case we fail to send it now.
1464                  */
1465                 rep->r_rtt = -1;
1466                 if (sbspace(&so->so_snd) >= rep->r_mreq->m_pkthdr.len &&
1467                     ((rpc->rc_flag & RPCCLNT_DUMBTIMR) ||
1468                      (rep->r_flags & R_SENT) ||
1469                      rpc->rc_sent < rpc->rc_cwnd) &&
1470                     (m = m_copym(rep->r_mreq, 0, M_COPYALL, M_DONTWAIT))) {
1471                         if ((rpc->rc_flag & RPCCLNT_NOCONN) == 0)
1472                                 error = (*so->so_proto->pr_usrreqs->pru_send) (so, 0, m,
1473                                                             NULL, NULL, td);
1474                         else
1475                                 error = (*so->so_proto->pr_usrreqs->pru_send)(so, 0, m, rpc->rc_name, NULL, td);
1476                         if (error) {
1477                                 if (RPCIGNORE_SOERROR(rpc->rc_soflags, error))
1478                                         so->so_error = 0;
1479                         } else {
1480                                 /*
1481                                  * Iff first send, start timing else turn
1482                                  * timing off, backoff timer and divide
1483                                  * congestion window by 2.
1484                                  */
1485                                 if (rep->r_flags & R_SENT) {
1486                                         rep->r_flags &= ~R_TIMING;
1487                                         if (++rep->r_rexmit > RPC_MAXREXMIT)
1488                                                 rep->r_rexmit = RPC_MAXREXMIT;
1489                                         rpc->rc_cwnd >>= 1;
1490                                         if (rpc->rc_cwnd < RPC_CWNDSCALE)
1491                                                 rpc->rc_cwnd = RPC_CWNDSCALE;
1492                                         rpcstats.rpcretries++;
1493                                 } else {
1494                                         rep->r_flags |= R_SENT;
1495                                         rpc->rc_sent += RPC_CWNDSCALE;
1496                                 }
1497                                 rep->r_rtt = 0;
1498                         }
1499                 }
1500         }
1501         mtx_unlock(&Giant);     /* rpc_msg -> tprintf */
1502         splx(s);
1503
1504 #ifdef __OpenBSD__
1505         timeout_add(rpcclnt_timer, to, rpcclnt_ticks);
1506 #else
1507         callout_reset(&rpcclnt_callout, rpcclnt_ticks, rpcclnt_timer, NULL);
1508 #endif
1509 }
1510
1511 /*
1512  * Test for a termination condition pending on the process. This is used for
1513  * RPCCLNT_INT mounts.
1514  */
1515 int
1516 rpcclnt_sigintr(rpc, task, pr)
1517         struct rpcclnt *rpc;
1518         struct rpctask *task;
1519         RPC_EXEC_CTX pr;
1520 {
1521         struct proc    *p;
1522
1523         sigset_t        tmpset;
1524
1525         if (rpc == NULL) 
1526                 return EFAULT;
1527
1528         /* XXX deal with forced unmounts */
1529
1530         if (task && (task->r_flags & R_SOFTTERM))
1531                 RPC_RETURN(EINTR);
1532
1533         if (!(rpc->rc_flag & RPCCLNT_INT))
1534                 RPC_RETURN(0);
1535
1536         if (pr == NULL)
1537                 return (0);
1538
1539 #ifdef __OpenBSD__
1540         p = pr;
1541         if (p && p->p_siglist &&
1542             (((p->p_siglist & ~p->p_sigmask) & ~p->p_sigignore) &
1543              RPCINT_SIGMASK))
1544                 RPC_RETURN(EINTR);
1545 #else
1546         p = pr->td_proc;
1547         PROC_LOCK(p);
1548         tmpset = p->p_siglist;
1549         SIGSETNAND(tmpset, pr->td_sigmask);
1550         mtx_lock(&p->p_sigacts->ps_mtx);
1551         SIGSETNAND(tmpset, p->p_sigacts->ps_sigignore);
1552         mtx_unlock(&p->p_sigacts->ps_mtx);
1553         if (SIGNOTEMPTY(p->p_siglist) && RPCCLNTINT_SIGMASK(tmpset)) {
1554                 PROC_UNLOCK(p);
1555                 RPC_RETURN(EINTR);
1556         }
1557         PROC_UNLOCK(p);
1558 #endif
1559         RPC_RETURN(0);
1560 }
1561
1562 /*
1563  * Lock a socket against others. Necessary for STREAM sockets to ensure you
1564  * get an entire rpc request/reply and also to avoid race conditions between
1565  * the processes with nfs requests in progress when a reconnect is necessary.
1566  */
1567 static int
1568 rpcclnt_sndlock(flagp, task)
1569         int            *flagp;
1570         struct rpctask *task;
1571 {
1572         RPC_EXEC_CTX p;
1573         int             slpflag = 0, slptimeo = 0;
1574
1575         p = task->r_td;
1576         if (task->r_rpcclnt->rc_flag & RPCCLNT_INT)
1577                 slpflag = PCATCH;
1578         while (*flagp & RPCCLNT_SNDLOCK) {
1579                 if (rpcclnt_sigintr(task->r_rpcclnt, task, p))
1580                         RPC_RETURN(EINTR);
1581                 *flagp |= RPCCLNT_WANTSND;
1582                 (void)tsleep((caddr_t) flagp, slpflag | (PZERO - 1), "rpcsndlck",
1583                              slptimeo);
1584                 if (slpflag == PCATCH) {
1585                         slpflag = 0;
1586                         slptimeo = 2 * hz;
1587                 }
1588         }
1589         *flagp |= RPCCLNT_SNDLOCK;
1590         RPC_RETURN(0);
1591 }
1592
1593 /*
1594  * Unlock the stream socket for others.
1595  */
1596 static void
1597 rpcclnt_sndunlock(flagp)
1598         int            *flagp;
1599 {
1600
1601         if ((*flagp & RPCCLNT_SNDLOCK) == 0)
1602                 panic("rpc sndunlock");
1603         *flagp &= ~RPCCLNT_SNDLOCK;
1604         if (*flagp & RPCCLNT_WANTSND) {
1605                 *flagp &= ~RPCCLNT_WANTSND;
1606                 wakeup((caddr_t) flagp);
1607         }
1608 }
1609
1610 static int
1611 rpcclnt_rcvlock(task)
1612         struct rpctask *task;
1613 {
1614         int            *flagp = &task->r_rpcclnt->rc_flag;
1615         int             slpflag, slptimeo = 0;
1616
1617         if (*flagp & RPCCLNT_INT)
1618                 slpflag = PCATCH;
1619         else
1620                 slpflag = 0;
1621         while (*flagp & RPCCLNT_RCVLOCK) {
1622                 if (rpcclnt_sigintr(task->r_rpcclnt, task, task->r_td))
1623                         RPC_RETURN(EINTR);
1624                 *flagp |= RPCCLNT_WANTRCV;
1625                 (void)tsleep((caddr_t) flagp, slpflag | (PZERO - 1), "rpcrcvlk",
1626                              slptimeo);
1627                 if (slpflag == PCATCH) {
1628                         slpflag = 0;
1629                         slptimeo = 2 * hz;
1630                 }
1631         }
1632         *flagp |= RPCCLNT_RCVLOCK;
1633         RPC_RETURN(0);
1634 }
1635
1636 /*
1637  * Unlock the stream socket for others.
1638  */
1639 static void
1640 rpcclnt_rcvunlock(flagp)
1641         int            *flagp;
1642 {
1643
1644         if ((*flagp & RPCCLNT_RCVLOCK) == 0)
1645                 panic("nfs rcvunlock");
1646         *flagp &= ~RPCCLNT_RCVLOCK;
1647         if (*flagp & RPCCLNT_WANTRCV) {
1648                 *flagp &= ~RPCCLNT_WANTRCV;
1649                 wakeup((caddr_t) flagp);
1650         }
1651 }
1652
1653 #if 0
1654 /*
1655  * Check for badly aligned mbuf data areas and realign data in an mbuf list
1656  * by copying the data areas up, as required.
1657  */
1658 void
1659 rpcclnt_realign(m, hsiz)
1660         struct mbuf    *m;
1661         int             hsiz;
1662 {
1663         struct mbuf    *m2;
1664         int             siz, mlen, olen;
1665         caddr_t         tcp, fcp;
1666         struct mbuf    *mnew;
1667
1668         while (m) {
1669                 /*
1670                  * This never happens for UDP, rarely happens for TCP but
1671                  * frequently happens for iso transport.
1672                  */
1673                 if ((m->m_len & 0x3) || (mtod(m, long)&0x3)) {
1674                         olen = m->m_len;
1675                         fcp = mtod(m, caddr_t);
1676                         if ((long)fcp & 0x3) {
1677                                 if (m->m_flags & M_PKTHDR)
1678                                         m_tag_delete_chain(m, NULL);
1679                                 m->m_flags &= ~M_PKTHDR;
1680                                 if (m->m_flags & M_EXT)
1681                                         m->m_data = m->m_ext.ext_buf +
1682                                                 ((m->m_ext.ext_size - olen) & ~0x3);
1683                                 else
1684                                         m->m_data = m->m_dat;
1685                         }
1686                         m->m_len = 0;
1687                         tcp = mtod(m, caddr_t);
1688                         mnew = m;
1689                         m2 = m->m_next;
1690
1691                         /*
1692                          * If possible, only put the first invariant part of
1693                          * the RPC header in the first mbuf.
1694                          */
1695                         mlen = M_TRAILINGSPACE(m);
1696                         if (olen <= hsiz && mlen > hsiz)
1697                                 mlen = hsiz;
1698
1699                         /* Loop through the mbuf list consolidating data. */
1700                         while (m) {
1701                                 while (olen > 0) {
1702                                         if (mlen == 0) {
1703                                                 if (m2->m_flags & M_PKTHDR)
1704                                                         m_tag_delete_chain(m2, NULL);
1705                                                 m2->m_flags &= ~M_PKTHDR;
1706                                                 if (m2->m_flags & M_EXT)
1707                                                         m2->m_data = m2->m_ext.ext_buf;
1708                                                 else
1709                                                         m2->m_data = m2->m_dat;
1710                                                 m2->m_len = 0;
1711                                                 mlen = M_TRAILINGSPACE(m2);
1712                                                 tcp = mtod(m2, caddr_t);
1713                                                 mnew = m2;
1714                                                 m2 = m2->m_next;
1715                                         }
1716                                         siz = min(mlen, olen);
1717                                         if (tcp != fcp)
1718                                                 bcopy(fcp, tcp, siz);
1719                                         mnew->m_len += siz;
1720                                         mlen -= siz;
1721                                         olen -= siz;
1722                                         tcp += siz;
1723                                         fcp += siz;
1724                                 }
1725                                 m = m->m_next;
1726                                 if (m) {
1727                                         olen = m->m_len;
1728                                         fcp = mtod(m, caddr_t);
1729                                 }
1730                         }
1731
1732                         /*
1733                          * Finally, set m_len == 0 for any trailing mbufs
1734                          * that have been copied out of.
1735                          */
1736                         while (m2) {
1737                                 m2->m_len = 0;
1738                                 m2 = m2->m_next;
1739                         }
1740                         return;
1741                 }
1742                 m = m->m_next;
1743         }
1744 }
1745 #else
1746 static void
1747 rpcclnt_realign(struct mbuf **pm, int hsiz)
1748 {
1749         struct mbuf *m;
1750         struct mbuf *n = NULL;
1751         int off = 0;
1752
1753         RPCDEBUG("in rpcclnt_realign()");
1754
1755         while ((m = *pm) != NULL) {
1756             if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) {
1757                 MGET(n, M_TRYWAIT, MT_DATA);
1758                 if (m->m_len >= MINCLSIZE) {
1759                     MCLGET(n, M_TRYWAIT);
1760                 }
1761                 n->m_len = 0;
1762                 break;
1763             }
1764             pm = &m->m_next;
1765         }
1766
1767         /*
1768         * If n is non-NULL, loop on m copying data, then replace the
1769         * portion of the chain that had to be realigned.
1770         */
1771         if (n != NULL) {
1772             while (m) {
1773                 m_copyback(n, off, m->m_len, mtod(m, caddr_t));
1774                 off += m->m_len;
1775                 m = m->m_next;
1776             }
1777             m_freem(*pm);
1778             *pm = n;
1779         }
1780
1781         RPCDEBUG("leave rpcclnt_realign()");
1782 }
1783 #endif
1784
1785 static int
1786 rpcclnt_msg(p, server, msg)
1787         RPC_EXEC_CTX   p;
1788         const char     *server;
1789         char           *msg;
1790 {
1791 #ifdef __OpenBSD__
1792         tpr_t           tpr;
1793         struct proc    *pr = p;
1794
1795         if (p)
1796                 tpr = tprintf_open(p);
1797         else
1798                 tpr = NULL;
1799         tprintf(tpr, "rpc server %s: %s\n", server, msg);
1800         tprintf_close(tpr);
1801         RPC_RETURN(0);
1802 #else
1803         GIANT_REQUIRED;
1804
1805         tprintf(p ? p->td_proc : NULL, LOG_INFO,
1806                 "nfs server %s: %s\n", server, msg);
1807         RPC_RETURN(0);
1808 #endif
1809 }
1810
1811 /*
1812  * Build the RPC header and fill in the authorization info. The authorization
1813  * string argument is only used when the credentials come from outside of the
1814  * kernel (AUTH_KERB). (likewise, the ucred is only used when inside the
1815  * kernel) Returns the head of the mbuf list.
1816  */
1817 static struct mbuf    *
1818 rpcclnt_buildheader(rc, procid, mrest, mrest_len, xidp, mheadend, cred)
1819         struct rpcclnt *rc;
1820         int             procid;
1821         struct mbuf    *mrest;
1822         u_int32_t       mrest_len;
1823         int            *xidp;
1824         struct mbuf   **mheadend;
1825         struct ucred * cred;
1826 {
1827         /* register */ struct mbuf *mb;
1828         register u_int32_t *tl;
1829         /* register */ caddr_t bpos;
1830         struct mbuf *mreq, *mb2;
1831         int error;
1832
1833         MGETHDR(mb, M_TRYWAIT, MT_DATA);
1834         if (6 * RPCX_UNSIGNED >= MINCLSIZE) {
1835                 MCLGET(mb, M_TRYWAIT);
1836         } else if (6 * RPCX_UNSIGNED < MHLEN) {
1837                 MH_ALIGN(mb, 6 * RPCX_UNSIGNED);
1838         } else {
1839                 RPCDEBUG("mbuf too small");
1840                 panic("cheap bailout");
1841         }
1842         mb->m_len = 0;
1843         mreq = mb;
1844         bpos = mtod(mb, caddr_t);
1845
1846         /*
1847          * First the RPC header.
1848          */
1849         rpcm_build(tl, u_int32_t *, 6 * RPCX_UNSIGNED);
1850
1851         /* Get a new (non-zero) xid */
1852         if ((rpcclnt_xid == 0) && (rpcclnt_xid_touched == 0)) {
1853                 rpcclnt_xid = arc4random();
1854                 rpcclnt_xid_touched = 1;
1855         } else {
1856                 while ((*xidp = arc4random() % 256) == 0);
1857                 rpcclnt_xid += *xidp;
1858         }
1859
1860         /* XXX: funky... */
1861         *tl++ = *xidp = txdr_unsigned(rpcclnt_xid);
1862
1863         *tl++ = rpc_call;
1864         *tl++ = rpc_vers;
1865         *tl++ = txdr_unsigned(rc->rc_prog->prog_id);
1866         *tl++ = txdr_unsigned(rc->rc_prog->prog_version);
1867         *tl++ = txdr_unsigned(procid);
1868
1869         if ((error = rpcauth_buildheader(rc->rc_auth, cred, &mb, &bpos))) {
1870                 RPCDEBUG("rpcauth_buildheader failed %d", error);
1871                 return NULL;
1872         }
1873
1874         mb->m_next = mrest;
1875         *mheadend = mb;
1876         mreq->m_pkthdr.len = m_length(mreq, NULL);
1877         mreq->m_pkthdr.rcvif = NULL;
1878         return (mreq);
1879 }
1880
1881 /*
1882  * Help break down an mbuf chain by setting the first siz bytes contiguous
1883  * pointed to by returned val. This is used by the macros rpcm_dissect and
1884  * rpcm_dissecton for tough cases. (The macros use the vars. dpos and dpos2)
1885  */
1886 static int
1887 rpcm_disct(mdp, dposp, siz, left, cp2)
1888         struct mbuf   **mdp;
1889         caddr_t        *dposp;
1890         int             siz;
1891         int             left;
1892         caddr_t        *cp2;
1893 {
1894         struct mbuf    *mp, *mp2;
1895         int             siz2, xfer;
1896         caddr_t         p;
1897
1898         mp = *mdp;
1899         while (left == 0) {
1900                 *mdp = mp = mp->m_next;
1901                 if (mp == NULL)
1902                         RPC_RETURN(EBADRPC);
1903                 left = mp->m_len;
1904                 *dposp = mtod(mp, caddr_t);
1905         }
1906         if (left >= siz) {
1907                 *cp2 = *dposp;
1908                 *dposp += siz;
1909         } else if (mp->m_next == NULL) {
1910                 RPC_RETURN(EBADRPC);
1911         } else if (siz > MHLEN) {
1912                 panic("rpc S too big");
1913         } else {
1914                 MGET(mp2, M_TRYWAIT, MT_DATA);
1915                 mp2->m_next = mp->m_next;
1916                 mp->m_next = mp2;
1917                 mp->m_len -= left;
1918                 mp = mp2;
1919                 *cp2 = p = mtod(mp, caddr_t);
1920                 bcopy(*dposp, p, left); /* Copy what was left */
1921                 siz2 = siz - left;
1922                 p += left;
1923                 mp2 = mp->m_next;
1924                 /* Loop around copying up the siz2 bytes */
1925                 while (siz2 > 0) {
1926                         if (mp2 == NULL)
1927                                 RPC_RETURN(EBADRPC);
1928                         xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
1929                         if (xfer > 0) {
1930                                 bcopy(mtod(mp2, caddr_t), p, xfer);
1931                                 RPCMADV(mp2, xfer);
1932                                 mp2->m_len -= xfer;
1933                                 p += xfer;
1934                                 siz2 -= xfer;
1935                         }
1936                         if (siz2 > 0)
1937                                 mp2 = mp2->m_next;
1938                 }
1939                 mp->m_len = siz;
1940                 *mdp = mp2;
1941                 *dposp = mtod(mp2, caddr_t);
1942         }
1943         RPC_RETURN(0);
1944 }
1945
1946
1947
1948 static u_int32_t
1949 rpcclnt_proct(rpc, procid)
1950         struct rpcclnt *rpc;
1951         u_int32_t       procid;
1952 {
1953         if (rpc->rc_proctlen != 0 && rpc->rc_proct != NULL &&
1954             procid < rpc->rc_proctlen) {
1955                 return rpc->rc_proct[procid];
1956         }
1957         return (0);
1958 }
1959
1960 static int
1961 rpc_adv(mdp, dposp, offs, left)
1962         struct mbuf   **mdp;
1963         caddr_t        *dposp;
1964         int             offs;
1965         int             left;
1966 {
1967         struct mbuf    *m;
1968         int             s;
1969
1970         m = *mdp;
1971         s = left;
1972         while (s < offs) {
1973                 offs -= s;
1974                 m = m->m_next;
1975                 if (m == NULL)
1976                         RPC_RETURN(EBADRPC);
1977                 s = m->m_len;
1978         }
1979         *mdp = m;
1980         *dposp = mtod(m, caddr_t) + offs;
1981         RPC_RETURN(0);
1982 }
1983
1984 int
1985 rpcclnt_cancelreqs(rpc)
1986         struct rpcclnt *rpc;
1987 {
1988         struct rpctask *task;
1989         int             i, s;
1990
1991         s = splnet();
1992         TAILQ_FOREACH(task, &rpctask_q, r_chain) {
1993                 if (rpc != task->r_rpcclnt || task->r_mrep != NULL ||
1994                     (task->r_flags & R_SOFTTERM))
1995                         continue;
1996                 rpcclnt_softterm(task);
1997         }
1998         splx(s);
1999
2000         for (i = 0; i < 30; i++) {
2001                 s = splnet();
2002                 TAILQ_FOREACH(task, &rpctask_q, r_chain) {
2003                         if (rpc == task->r_rpcclnt)
2004                                 break;
2005                 }
2006                 splx(s);
2007                 if (task == NULL)
2008                         return (0);
2009                 tsleep(&lbolt, PSOCK, "nfscancel", 0);
2010         }
2011         return (EBUSY);
2012 }
2013
2014 static void
2015 rpcclnt_softterm(struct rpctask * task)
2016 {
2017         task->r_flags |= R_SOFTTERM;
2018         if (task->r_flags & R_SENT) {
2019                 task->r_rpcclnt->rc_sent -= RPC_CWNDSCALE;
2020                 task->r_flags &= ~R_SENT;
2021         }
2022 }
2023
2024
2025 #ifndef __OpenBSD__
2026 /* called by rpcclnt_get() */
2027 void
2028 rpcclnt_create(struct rpcclnt ** rpc)
2029 {
2030         MALLOC(*rpc, struct rpcclnt *, sizeof(struct rpcclnt), M_RPC, M_WAITOK | M_ZERO);
2031 }
2032
2033 /* called by rpcclnt_put() */
2034 void
2035 rpcclnt_destroy(struct rpcclnt * rpc)
2036 {
2037         if (rpc != NULL) {
2038                 FREE(rpc, M_RPC);
2039         } else {
2040                 RPCDEBUG("attempting to free a NULL rpcclnt (not dereferenced)");
2041         }
2042 }
2043 #endif                          /* !__OpenBSD__ */
2044
2045
2046 /* XXX: add a lock around the auth structure in struct rpcclnt and make this
2047  * call safe for calling durring a connection */
2048 static int
2049 rpcauth_buildheader(struct rpc_auth * auth, struct ucred * cred, struct mbuf ** mhdr, caddr_t * bp)
2050 {
2051         size_t authsiz, verfsiz;
2052         uint32_t mlen, grpsiz;
2053         register struct mbuf *mb, *mb2;
2054         caddr_t bpos;
2055         register u_int32_t *tl;
2056         register int i;
2057
2058         if (auth == NULL || mhdr == NULL)
2059           return EFAULT;
2060
2061         switch (auth->auth_type) {
2062         case RPCAUTH_NULL:
2063                 authsiz = 0;
2064                 verfsiz = 0;
2065         break;
2066         case RPCAUTH_UNIX:
2067                 authsiz = (5 + cred->cr_ngroups) * RPCX_UNSIGNED;
2068                 verfsiz = 0;
2069         break;
2070         default:
2071                 return EPROTONOSUPPORT;
2072         break;
2073         };
2074
2075         mlen = rpcm_rndup(authsiz) + rpcm_rndup(verfsiz) + 4 * RPCX_UNSIGNED;
2076
2077         mb = *mhdr;
2078         bpos = *bp;
2079
2080         rpcm_build(tl, u_int32_t *, mlen);
2081
2082         *bp = bpos;
2083         *mhdr = mb;
2084
2085         *tl++ = txdr_unsigned(auth->auth_type);
2086         *tl++ = txdr_unsigned(authsiz);
2087         switch (auth->auth_type) {
2088         case RPCAUTH_UNIX:
2089                 *tl++ = 0;
2090                 *tl++ = 0; 
2091
2092                 *tl++ = txdr_unsigned(cred->cr_uid);
2093                 *tl++ = txdr_unsigned(cred->cr_groups[0]);
2094                 grpsiz = cred->cr_ngroups;
2095                 *tl++ = txdr_unsigned(grpsiz);
2096                 /* XXX: groups[0] is already sent... */
2097                 for (i = 0 ; i < grpsiz ; i++) {
2098                          *tl++ = txdr_unsigned(cred->cr_groups[i]);
2099                 }
2100
2101                 /* null verification header */
2102                 *tl++ = txdr_unsigned(RPCAUTH_NULL);
2103                 *tl++ = 0;
2104         break;
2105         case RPCAUTH_NULL:
2106                 /* just a null verf header */
2107                 *tl++ = txdr_unsigned(RPCAUTH_NULL);
2108                 *tl = 0;
2109         break;
2110         default:
2111                 panic("inconsistent rpc auth type");
2112         break;
2113         }
2114
2115         return 0;
2116 }