rpc.c revision 1.1 1 /*
2 * Copyright (c) 1992 Regents of the University of California.
3 * All rights reserved.
4 *
5 * This software was developed by the Computer Systems Engineering group
6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7 * contributed to Berkeley.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by the University of
20 * California, Lawrence Berkeley Laboratory and its contributors.
21 * 4. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * from @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL)
38 * $Id: rpc.c,v 1.1 1994/05/08 16:11:35 brezak Exp $
39 */
40
41 #include <sys/param.h>
42 #include <sys/socket.h>
43
44 #include <netinet/in.h>
45 #include <netinet/in_systm.h>
46
47 #include <nfs/rpcv2.h>
48 #include <nfs/nfsv2.h>
49 #undef NFSX_FATTR
50 #include <string.h>
51
52 #include "stand.h"
53 #include "net.h"
54 #include "netif.h"
55 #include "rpc.h"
56
57 /* XXX Data part of nfs rpc reply (also the largest thing we receive) */
58 struct nfs_reply_data {
59 u_long errno;
60 #ifndef NFSX_FATTR
61 struct nfsv2_fattr fa;
62 #else
63 u_char fa[NFSX_FATTR(0)];
64 #endif
65 u_long count;
66 u_char data[1200];
67 };
68 #define NFSREAD_SIZE sizeof(((struct nfs_reply_data *)0)->data)
69
70 /* Cache stuff */
71 #define PMAP_NUM 8 /* need at most 5 pmap entries */
72
73 static struct pmap_list {
74 u_long addr; /* address of server */
75 u_long prog;
76 u_long vers;
77 u_short port; /* cached port for service */
78 } pmap_list[PMAP_NUM] = {
79 { 0, PMAPPROG, PMAPVERS, PMAPPORT }
80 };
81 static int pmap_num = 1;
82
83 /* Local forwards */
84 static int recvrpc __P((struct iodesc *, void *, int));
85
86 /* Make a rpc call; return length of answer */
87 int
88 callrpc(d, prog, vers, proc, sdata, slen, rdata, rlen)
89 register struct iodesc *d;
90 register u_long prog, vers, proc;
91 register void *sdata;
92 register int slen;
93 register void *rdata;
94 register int rlen;
95 {
96 register int cc;
97 register struct rpc_call *rpc;
98 struct {
99 u_char header[HEADER_SIZE];
100 struct rpc_call wrpc;
101 u_char data[sizeof(struct nfs_reply_data)]; /* XXX */
102 } wbuf;
103 struct {
104 u_char header[HEADER_SIZE];
105 struct rpc_reply rrpc;
106 union {
107 u_long errno;
108 u_char data[sizeof(struct nfs_reply_data)];
109 } ru;
110 } rbuf;
111
112 #ifdef RPC_DEBUG
113 if (debug)
114 printf("callrpc: called\n");
115 #endif
116 if (rlen > sizeof(rbuf.ru.data))
117 panic("callrpc: huge read (%d > %d)",
118 rlen, sizeof(rbuf.ru.data));
119
120 d->destport = getport(d, prog, vers);
121
122 rpc = &wbuf.wrpc;
123
124 bzero(rpc, sizeof(*rpc));
125
126 rpc->rp_xid = d->xid;
127 rpc->rp_rpcvers = htonl(RPC_MSG_VERSION);
128 rpc->rp_prog = htonl(prog);
129 rpc->rp_vers = htonl(vers);
130 rpc->rp_proc = htonl(proc);
131 bcopy(sdata, wbuf.data, slen);
132
133 cc = sendrecv(d, sendudp, rpc, sizeof(*rpc) + slen, recvrpc,
134 ((u_char *)&rbuf.rrpc) - HEADER_SIZE, sizeof(rbuf) - HEADER_SIZE);
135
136 if (cc < rlen) {
137 /* Check for an error return */
138 if (cc >= sizeof(rbuf.ru.errno) && rbuf.ru.errno != 0) {
139 errno = ntohl(rbuf.ru.errno);
140 return (-1);
141 }
142 panic("callrpc: missing data (%d < %d)", cc, rlen);
143 }
144 if (cc > sizeof(rbuf.ru.data))
145 panic("callrpc: huge return (%d > %d)",
146 cc, sizeof(rbuf.ru.data));
147 bcopy(rbuf.ru.data, rdata, cc);
148 return (cc);
149 }
150
151 /* Returns true if packet is the one we're waiting for */
152 static int
153 recvrpc(d, pkt, len)
154 register struct iodesc *d;
155 register void *pkt;
156 int len;
157 {
158 register struct rpc_reply *rpc;
159
160 errno = 0;
161 #ifdef RPC_DEBUG
162 if (debug)
163 printf("recvrpc: called\n");
164 #endif
165 rpc = (struct rpc_reply *)checkudp(d, pkt, &len);
166 if (rpc == NULL || len < sizeof(*rpc)) {
167 #ifdef RPC_DEBUG
168 if (debug)
169 printf("recvrpc: bad response rpc=%x len=%d\n",
170 (u_int)rpc, len);
171 #endif
172 return (-1);
173 }
174
175 NTOHL(rpc->rp_direction);
176 NTOHL(rpc->rp_stat);
177
178 if (rpc->rp_xid != d->xid || rpc->rp_direction != REPLY ||
179 rpc->rp_stat != MSG_ACCEPTED) {
180 #ifdef RPC_DEBUG
181 if (debug) {
182 if (rpc->rp_xid != d->xid)
183 printf("recvrpc: rp_xid %d != xid %d\n",
184 rpc->rp_xid, d->xid);
185 if (rpc->rp_direction != REPLY)
186 printf("recvrpc: %d != REPLY\n", rpc->rp_direction);
187 if (rpc->rp_stat != MSG_ACCEPTED)
188 printf("recvrpc: %d != MSG_ACCEPTED\n", rpc->rp_stat);
189 }
190 #endif
191 return (-1);
192 }
193
194 /* Bump xid so next request will be unique */
195 ++d->xid;
196
197 /* Return data count (thus indicating success) */
198 return (len - sizeof(*rpc));
199 }
200
201 /* Request a port number from the port mapper */
202 u_short
203 getport(d, prog, vers)
204 register struct iodesc *d;
205 u_long prog;
206 u_long vers;
207 {
208 register int i;
209 register struct pmap_list *pl;
210 u_long port;
211 struct {
212 u_long prog; /* call program */
213 u_long vers; /* call version */
214 u_long proto; /* call protocol */
215 u_long port; /* call port (unused) */
216 } sdata;
217
218 #ifdef RPC_DEBUG
219 if (debug)
220 printf("getport: called\n");
221 #endif
222 /* Try for cached answer first */
223 for (i = 0, pl = pmap_list; i < pmap_num; ++i, ++pl)
224 if ((pl->addr == d->destip || pl->addr == 0) &&
225 pl->prog == prog && pl->vers == vers)
226 return (pl->port);
227
228 /* Don't overflow cache */
229 if (pmap_num > PMAP_NUM - 1)
230 panic("getport: overflowed pmap_list!");
231
232 sdata.prog = htonl(prog);
233 sdata.vers = htonl(vers);
234 sdata.proto = htonl(IPPROTO_UDP);
235 sdata.port = 0;
236
237 if (callrpc(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
238 &sdata, sizeof(sdata), &port, sizeof(port)) < 0) {
239 printf("getport: %s", strerror(errno));
240 return(-1);
241 }
242
243 /* Cache answer */
244 pl->addr = d->destip;
245 pl->prog = prog;
246 pl->vers = vers;
247 pl->port = port;
248 ++pmap_num;
249
250 return ((u_short)port);
251 }
252