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