xref: /minix3/sys/lib/libsa/rpc.c (revision 58a2b0008e28f606a7f7f5faaeaba4faac57a1ea)
1*58a2b000SEvgeniy Ivanov /*	$NetBSD: rpc.c,v 1.29 2009/01/17 14:00:36 tsutsui Exp $	*/
2*58a2b000SEvgeniy Ivanov 
3*58a2b000SEvgeniy Ivanov /*
4*58a2b000SEvgeniy Ivanov  * Copyright (c) 1992 Regents of the University of California.
5*58a2b000SEvgeniy Ivanov  * All rights reserved.
6*58a2b000SEvgeniy Ivanov  *
7*58a2b000SEvgeniy Ivanov  * This software was developed by the Computer Systems Engineering group
8*58a2b000SEvgeniy Ivanov  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9*58a2b000SEvgeniy Ivanov  * contributed to Berkeley.
10*58a2b000SEvgeniy Ivanov  *
11*58a2b000SEvgeniy Ivanov  * Redistribution and use in source and binary forms, with or without
12*58a2b000SEvgeniy Ivanov  * modification, are permitted provided that the following conditions
13*58a2b000SEvgeniy Ivanov  * are met:
14*58a2b000SEvgeniy Ivanov  * 1. Redistributions of source code must retain the above copyright
15*58a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer.
16*58a2b000SEvgeniy Ivanov  * 2. Redistributions in binary form must reproduce the above copyright
17*58a2b000SEvgeniy Ivanov  *    notice, this list of conditions and the following disclaimer in the
18*58a2b000SEvgeniy Ivanov  *    documentation and/or other materials provided with the distribution.
19*58a2b000SEvgeniy Ivanov  * 3. All advertising materials mentioning features or use of this software
20*58a2b000SEvgeniy Ivanov  *    must display the following acknowledgement:
21*58a2b000SEvgeniy Ivanov  *	This product includes software developed by the University of
22*58a2b000SEvgeniy Ivanov  *	California, Lawrence Berkeley Laboratory and its contributors.
23*58a2b000SEvgeniy Ivanov  * 4. Neither the name of the University nor the names of its contributors
24*58a2b000SEvgeniy Ivanov  *    may be used to endorse or promote products derived from this software
25*58a2b000SEvgeniy Ivanov  *    without specific prior written permission.
26*58a2b000SEvgeniy Ivanov  *
27*58a2b000SEvgeniy Ivanov  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28*58a2b000SEvgeniy Ivanov  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29*58a2b000SEvgeniy Ivanov  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30*58a2b000SEvgeniy Ivanov  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31*58a2b000SEvgeniy Ivanov  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32*58a2b000SEvgeniy Ivanov  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33*58a2b000SEvgeniy Ivanov  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34*58a2b000SEvgeniy Ivanov  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35*58a2b000SEvgeniy Ivanov  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36*58a2b000SEvgeniy Ivanov  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37*58a2b000SEvgeniy Ivanov  * SUCH DAMAGE.
38*58a2b000SEvgeniy Ivanov  *
39*58a2b000SEvgeniy Ivanov  * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp  (LBL)
40*58a2b000SEvgeniy Ivanov  */
41*58a2b000SEvgeniy Ivanov 
42*58a2b000SEvgeniy Ivanov /*
43*58a2b000SEvgeniy Ivanov  * RPC functions used by NFS and bootparams.
44*58a2b000SEvgeniy Ivanov  * Note that bootparams requires the ability to find out the
45*58a2b000SEvgeniy Ivanov  * address of the server from which its response has come.
46*58a2b000SEvgeniy Ivanov  * This is supported by keeping the IP/UDP headers in the
47*58a2b000SEvgeniy Ivanov  * buffer space provided by the caller.  (See rpc_fromaddr)
48*58a2b000SEvgeniy Ivanov  */
49*58a2b000SEvgeniy Ivanov 
50*58a2b000SEvgeniy Ivanov #include <sys/param.h>
51*58a2b000SEvgeniy Ivanov #include <sys/socket.h>
52*58a2b000SEvgeniy Ivanov 
53*58a2b000SEvgeniy Ivanov #include <netinet/in.h>
54*58a2b000SEvgeniy Ivanov #include <netinet/in_systm.h>
55*58a2b000SEvgeniy Ivanov 
56*58a2b000SEvgeniy Ivanov #ifdef _STANDALONE
57*58a2b000SEvgeniy Ivanov #include <lib/libkern/libkern.h>
58*58a2b000SEvgeniy Ivanov #include "stand.h"
59*58a2b000SEvgeniy Ivanov #else
60*58a2b000SEvgeniy Ivanov #include <string.h>
61*58a2b000SEvgeniy Ivanov #include <errno.h>
62*58a2b000SEvgeniy Ivanov #include <stdio.h>
63*58a2b000SEvgeniy Ivanov #endif
64*58a2b000SEvgeniy Ivanov 
65*58a2b000SEvgeniy Ivanov #include "rpcv2.h"
66*58a2b000SEvgeniy Ivanov 
67*58a2b000SEvgeniy Ivanov #include "net.h"
68*58a2b000SEvgeniy Ivanov #include "rpc.h"
69*58a2b000SEvgeniy Ivanov 
70*58a2b000SEvgeniy Ivanov struct auth_info {
71*58a2b000SEvgeniy Ivanov 	int32_t 	authtype;	/* auth type */
72*58a2b000SEvgeniy Ivanov 	u_int32_t	authlen;	/* auth length */
73*58a2b000SEvgeniy Ivanov };
74*58a2b000SEvgeniy Ivanov 
75*58a2b000SEvgeniy Ivanov struct auth_unix {
76*58a2b000SEvgeniy Ivanov 	int32_t   ua_time;
77*58a2b000SEvgeniy Ivanov 	int32_t   ua_hostname;	/* null */
78*58a2b000SEvgeniy Ivanov 	int32_t   ua_uid;
79*58a2b000SEvgeniy Ivanov 	int32_t   ua_gid;
80*58a2b000SEvgeniy Ivanov 	int32_t   ua_gidlist;	/* null */
81*58a2b000SEvgeniy Ivanov };
82*58a2b000SEvgeniy Ivanov 
83*58a2b000SEvgeniy Ivanov struct rpc_call {
84*58a2b000SEvgeniy Ivanov 	u_int32_t	rp_xid;		/* request transaction id */
85*58a2b000SEvgeniy Ivanov 	int32_t 	rp_direction;	/* call direction (0) */
86*58a2b000SEvgeniy Ivanov 	u_int32_t	rp_rpcvers;	/* rpc version (2) */
87*58a2b000SEvgeniy Ivanov 	u_int32_t	rp_prog;	/* program */
88*58a2b000SEvgeniy Ivanov 	u_int32_t	rp_vers;	/* version */
89*58a2b000SEvgeniy Ivanov 	u_int32_t	rp_proc;	/* procedure */
90*58a2b000SEvgeniy Ivanov };
91*58a2b000SEvgeniy Ivanov 
92*58a2b000SEvgeniy Ivanov struct rpc_reply {
93*58a2b000SEvgeniy Ivanov 	u_int32_t	rp_xid;		/* request transaction id */
94*58a2b000SEvgeniy Ivanov 	int32_t 	rp_direction;	/* call direction (1) */
95*58a2b000SEvgeniy Ivanov 	int32_t 	rp_astatus;	/* accept status (0: accepted) */
96*58a2b000SEvgeniy Ivanov 	union {
97*58a2b000SEvgeniy Ivanov 		u_int32_t	rpu_errno;
98*58a2b000SEvgeniy Ivanov 		struct {
99*58a2b000SEvgeniy Ivanov 			struct auth_info rok_auth;
100*58a2b000SEvgeniy Ivanov 			u_int32_t	rok_status;
101*58a2b000SEvgeniy Ivanov 		} rpu_rok;
102*58a2b000SEvgeniy Ivanov 	} rp_u;
103*58a2b000SEvgeniy Ivanov };
104*58a2b000SEvgeniy Ivanov 
105*58a2b000SEvgeniy Ivanov /* Local forwards */
106*58a2b000SEvgeniy Ivanov static	ssize_t recvrpc(struct iodesc *, void *, size_t, saseconds_t);
107*58a2b000SEvgeniy Ivanov 
108*58a2b000SEvgeniy Ivanov int rpc_xid;
109*58a2b000SEvgeniy Ivanov int rpc_port = 0x400;	/* predecrement */
110*58a2b000SEvgeniy Ivanov 
111*58a2b000SEvgeniy Ivanov /*
112*58a2b000SEvgeniy Ivanov  * Make a rpc call; return length of answer
113*58a2b000SEvgeniy Ivanov  * Note: Caller must leave room for headers.
114*58a2b000SEvgeniy Ivanov  */
115*58a2b000SEvgeniy Ivanov ssize_t
rpc_call(struct iodesc * d,n_long prog,n_long vers,n_long proc,void * sdata,size_t slen,void * rdata,size_t rlen)116*58a2b000SEvgeniy Ivanov rpc_call(struct iodesc *d, n_long prog, n_long vers, n_long proc,
117*58a2b000SEvgeniy Ivanov 	void *sdata, size_t slen, void *rdata, size_t rlen)
118*58a2b000SEvgeniy Ivanov {
119*58a2b000SEvgeniy Ivanov 	ssize_t cc;
120*58a2b000SEvgeniy Ivanov 	struct auth_info *auth;
121*58a2b000SEvgeniy Ivanov 	struct rpc_call *call;
122*58a2b000SEvgeniy Ivanov 	struct rpc_reply *reply;
123*58a2b000SEvgeniy Ivanov 	char *send_head, *send_tail;
124*58a2b000SEvgeniy Ivanov 	char *recv_head, *recv_tail;
125*58a2b000SEvgeniy Ivanov 	n_long x;
126*58a2b000SEvgeniy Ivanov 	int port;	/* host order */
127*58a2b000SEvgeniy Ivanov 
128*58a2b000SEvgeniy Ivanov #ifdef RPC_DEBUG
129*58a2b000SEvgeniy Ivanov 	if (debug)
130*58a2b000SEvgeniy Ivanov 		printf("rpc_call: prog=0x%x vers=%d proc=%d\n",
131*58a2b000SEvgeniy Ivanov 		    prog, vers, proc);
132*58a2b000SEvgeniy Ivanov #endif
133*58a2b000SEvgeniy Ivanov 
134*58a2b000SEvgeniy Ivanov 	port = rpc_getport(d, prog, vers);
135*58a2b000SEvgeniy Ivanov 	if (port == -1)
136*58a2b000SEvgeniy Ivanov 		return -1;
137*58a2b000SEvgeniy Ivanov 
138*58a2b000SEvgeniy Ivanov 	d->destport = htons(port);
139*58a2b000SEvgeniy Ivanov 
140*58a2b000SEvgeniy Ivanov 	/*
141*58a2b000SEvgeniy Ivanov 	 * Prepend authorization stuff and headers.
142*58a2b000SEvgeniy Ivanov 	 * Note, must prepend things in reverse order.
143*58a2b000SEvgeniy Ivanov 	 */
144*58a2b000SEvgeniy Ivanov 	send_head = sdata;
145*58a2b000SEvgeniy Ivanov 	send_tail = (char *)sdata + slen;
146*58a2b000SEvgeniy Ivanov 
147*58a2b000SEvgeniy Ivanov 	/* Auth verifier is always auth_null */
148*58a2b000SEvgeniy Ivanov 	send_head -= sizeof(*auth);
149*58a2b000SEvgeniy Ivanov 	auth = (struct auth_info *)send_head;
150*58a2b000SEvgeniy Ivanov 	auth->authtype = htonl(RPCAUTH_NULL);
151*58a2b000SEvgeniy Ivanov 	auth->authlen = 0;
152*58a2b000SEvgeniy Ivanov 
153*58a2b000SEvgeniy Ivanov #if 1
154*58a2b000SEvgeniy Ivanov 	/* Auth credentials: always auth unix (as root) */
155*58a2b000SEvgeniy Ivanov 	send_head -= sizeof(struct auth_unix);
156*58a2b000SEvgeniy Ivanov 	(void)memset(send_head, 0, sizeof(struct auth_unix));
157*58a2b000SEvgeniy Ivanov 	send_head -= sizeof(*auth);
158*58a2b000SEvgeniy Ivanov 	auth = (struct auth_info *)send_head;
159*58a2b000SEvgeniy Ivanov 	auth->authtype = htonl(RPCAUTH_UNIX);
160*58a2b000SEvgeniy Ivanov 	auth->authlen = htonl(sizeof(struct auth_unix));
161*58a2b000SEvgeniy Ivanov #else
162*58a2b000SEvgeniy Ivanov 	/* Auth credentials: always auth_null (XXX OK?) */
163*58a2b000SEvgeniy Ivanov 	send_head -= sizeof(*auth);
164*58a2b000SEvgeniy Ivanov 	auth = send_head;
165*58a2b000SEvgeniy Ivanov 	auth->authtype = htonl(RPCAUTH_NULL);
166*58a2b000SEvgeniy Ivanov 	auth->authlen = 0;
167*58a2b000SEvgeniy Ivanov #endif
168*58a2b000SEvgeniy Ivanov 
169*58a2b000SEvgeniy Ivanov 	/* RPC call structure. */
170*58a2b000SEvgeniy Ivanov 	send_head -= sizeof(*call);
171*58a2b000SEvgeniy Ivanov 	call = (struct rpc_call *)send_head;
172*58a2b000SEvgeniy Ivanov 	rpc_xid++;
173*58a2b000SEvgeniy Ivanov 	call->rp_xid       = htonl(rpc_xid);
174*58a2b000SEvgeniy Ivanov 	call->rp_direction = htonl(RPC_CALL);
175*58a2b000SEvgeniy Ivanov 	call->rp_rpcvers   = htonl(RPC_VER2);
176*58a2b000SEvgeniy Ivanov 	call->rp_prog = htonl(prog);
177*58a2b000SEvgeniy Ivanov 	call->rp_vers = htonl(vers);
178*58a2b000SEvgeniy Ivanov 	call->rp_proc = htonl(proc);
179*58a2b000SEvgeniy Ivanov 
180*58a2b000SEvgeniy Ivanov 	/* Make room for the rpc_reply header. */
181*58a2b000SEvgeniy Ivanov 	recv_head = rdata;
182*58a2b000SEvgeniy Ivanov 	recv_tail = (char *)rdata + rlen;
183*58a2b000SEvgeniy Ivanov 	recv_head -= sizeof(*reply);
184*58a2b000SEvgeniy Ivanov 
185*58a2b000SEvgeniy Ivanov 	cc = sendrecv(d,
186*58a2b000SEvgeniy Ivanov 	    sendudp, send_head, send_tail - send_head,
187*58a2b000SEvgeniy Ivanov 	    recvrpc, recv_head, recv_tail - recv_head);
188*58a2b000SEvgeniy Ivanov 
189*58a2b000SEvgeniy Ivanov #ifdef RPC_DEBUG
190*58a2b000SEvgeniy Ivanov 	if (debug)
191*58a2b000SEvgeniy Ivanov 		printf("callrpc: cc=%ld rlen=%lu\n", (long)cc, (u_long)rlen);
192*58a2b000SEvgeniy Ivanov #endif
193*58a2b000SEvgeniy Ivanov 	if (cc == -1)
194*58a2b000SEvgeniy Ivanov 		return -1;
195*58a2b000SEvgeniy Ivanov 
196*58a2b000SEvgeniy Ivanov 	if ((size_t)cc <= sizeof(*reply)) {
197*58a2b000SEvgeniy Ivanov 		errno = EBADRPC;
198*58a2b000SEvgeniy Ivanov 		return -1;
199*58a2b000SEvgeniy Ivanov 	}
200*58a2b000SEvgeniy Ivanov 
201*58a2b000SEvgeniy Ivanov 	recv_tail = recv_head + cc;
202*58a2b000SEvgeniy Ivanov 
203*58a2b000SEvgeniy Ivanov 	/*
204*58a2b000SEvgeniy Ivanov 	 * Check the RPC reply status.
205*58a2b000SEvgeniy Ivanov 	 * The xid, dir, astatus were already checked.
206*58a2b000SEvgeniy Ivanov 	 */
207*58a2b000SEvgeniy Ivanov 	reply = (struct rpc_reply *)recv_head;
208*58a2b000SEvgeniy Ivanov 	auth = &reply->rp_u.rpu_rok.rok_auth;
209*58a2b000SEvgeniy Ivanov 	x = ntohl(auth->authlen);
210*58a2b000SEvgeniy Ivanov 	if (x != 0) {
211*58a2b000SEvgeniy Ivanov #ifdef RPC_DEBUG
212*58a2b000SEvgeniy Ivanov 		if (debug)
213*58a2b000SEvgeniy Ivanov 			printf("callrpc: reply auth != NULL\n");
214*58a2b000SEvgeniy Ivanov #endif
215*58a2b000SEvgeniy Ivanov 		errno = EBADRPC;
216*58a2b000SEvgeniy Ivanov 		return -1;
217*58a2b000SEvgeniy Ivanov 	}
218*58a2b000SEvgeniy Ivanov 	x = ntohl(reply->rp_u.rpu_rok.rok_status);
219*58a2b000SEvgeniy Ivanov 	if (x != 0) {
220*58a2b000SEvgeniy Ivanov 		printf("callrpc: error = %d\n", x);
221*58a2b000SEvgeniy Ivanov 		errno = EBADRPC;
222*58a2b000SEvgeniy Ivanov 		return -1;
223*58a2b000SEvgeniy Ivanov 	}
224*58a2b000SEvgeniy Ivanov 	recv_head += sizeof(*reply);
225*58a2b000SEvgeniy Ivanov 
226*58a2b000SEvgeniy Ivanov 	return (ssize_t)(recv_tail - recv_head);
227*58a2b000SEvgeniy Ivanov }
228*58a2b000SEvgeniy Ivanov 
229*58a2b000SEvgeniy Ivanov /*
230*58a2b000SEvgeniy Ivanov  * Returns true if packet is the one we're waiting for.
231*58a2b000SEvgeniy Ivanov  * This just checks the XID, direction, acceptance.
232*58a2b000SEvgeniy Ivanov  * Remaining checks are done by callrpc
233*58a2b000SEvgeniy Ivanov  */
234*58a2b000SEvgeniy Ivanov static ssize_t
recvrpc(struct iodesc * d,void * pkt,size_t len,saseconds_t tleft)235*58a2b000SEvgeniy Ivanov recvrpc(struct iodesc *d, void *pkt, size_t len, saseconds_t tleft)
236*58a2b000SEvgeniy Ivanov {
237*58a2b000SEvgeniy Ivanov 	struct rpc_reply *reply;
238*58a2b000SEvgeniy Ivanov 	ssize_t	n;
239*58a2b000SEvgeniy Ivanov 	int	x;
240*58a2b000SEvgeniy Ivanov 
241*58a2b000SEvgeniy Ivanov 	errno = 0;
242*58a2b000SEvgeniy Ivanov #ifdef RPC_DEBUG
243*58a2b000SEvgeniy Ivanov 	if (debug)
244*58a2b000SEvgeniy Ivanov 		printf("recvrpc: called len=%lu\n", (u_long)len);
245*58a2b000SEvgeniy Ivanov #endif
246*58a2b000SEvgeniy Ivanov 
247*58a2b000SEvgeniy Ivanov 	n = readudp(d, pkt, len, tleft);
248*58a2b000SEvgeniy Ivanov 	if (n <= (4 * 4))
249*58a2b000SEvgeniy Ivanov 		return -1;
250*58a2b000SEvgeniy Ivanov 
251*58a2b000SEvgeniy Ivanov 	reply = (struct rpc_reply *)pkt;
252*58a2b000SEvgeniy Ivanov 
253*58a2b000SEvgeniy Ivanov 	x = ntohl(reply->rp_xid);
254*58a2b000SEvgeniy Ivanov 	if (x != rpc_xid) {
255*58a2b000SEvgeniy Ivanov #ifdef RPC_DEBUG
256*58a2b000SEvgeniy Ivanov 		if (debug)
257*58a2b000SEvgeniy Ivanov 			printf("recvrpc: rp_xid %d != xid %d\n", x, rpc_xid);
258*58a2b000SEvgeniy Ivanov #endif
259*58a2b000SEvgeniy Ivanov 		return -1;
260*58a2b000SEvgeniy Ivanov 	}
261*58a2b000SEvgeniy Ivanov 
262*58a2b000SEvgeniy Ivanov 	x = ntohl(reply->rp_direction);
263*58a2b000SEvgeniy Ivanov 	if (x != RPC_REPLY) {
264*58a2b000SEvgeniy Ivanov #ifdef RPC_DEBUG
265*58a2b000SEvgeniy Ivanov 		if (debug)
266*58a2b000SEvgeniy Ivanov 			printf("recvrpc: rp_direction %d != REPLY\n", x);
267*58a2b000SEvgeniy Ivanov #endif
268*58a2b000SEvgeniy Ivanov 		return -1;
269*58a2b000SEvgeniy Ivanov 	}
270*58a2b000SEvgeniy Ivanov 
271*58a2b000SEvgeniy Ivanov 	x = ntohl(reply->rp_astatus);
272*58a2b000SEvgeniy Ivanov 	if (x != RPC_MSGACCEPTED) {
273*58a2b000SEvgeniy Ivanov 		errno = ntohl(reply->rp_u.rpu_errno);
274*58a2b000SEvgeniy Ivanov 		printf("recvrpc: reject, astat=%d, errno=%d\n", x, errno);
275*58a2b000SEvgeniy Ivanov 		return -1;
276*58a2b000SEvgeniy Ivanov 	}
277*58a2b000SEvgeniy Ivanov 
278*58a2b000SEvgeniy Ivanov 	/* Return data count (thus indicating success) */
279*58a2b000SEvgeniy Ivanov 	return n;
280*58a2b000SEvgeniy Ivanov }
281*58a2b000SEvgeniy Ivanov 
282*58a2b000SEvgeniy Ivanov /*
283*58a2b000SEvgeniy Ivanov  * Given a pointer to a reply just received,
284*58a2b000SEvgeniy Ivanov  * dig out the IP address/port from the headers.
285*58a2b000SEvgeniy Ivanov  */
286*58a2b000SEvgeniy Ivanov void
rpc_fromaddr(void * pkt,struct in_addr * addr,u_short * port)287*58a2b000SEvgeniy Ivanov rpc_fromaddr(void *pkt, struct in_addr *addr, u_short *port)
288*58a2b000SEvgeniy Ivanov {
289*58a2b000SEvgeniy Ivanov 	struct hackhdr {
290*58a2b000SEvgeniy Ivanov 		/* Tail of IP header: just IP addresses */
291*58a2b000SEvgeniy Ivanov 		n_long ip_src;
292*58a2b000SEvgeniy Ivanov 		n_long ip_dst;
293*58a2b000SEvgeniy Ivanov 		/* UDP header: */
294*58a2b000SEvgeniy Ivanov 		u_int16_t uh_sport;		/* source port */
295*58a2b000SEvgeniy Ivanov 		u_int16_t uh_dport;		/* destination port */
296*58a2b000SEvgeniy Ivanov 		int16_t	  uh_ulen;		/* udp length */
297*58a2b000SEvgeniy Ivanov 		u_int16_t uh_sum;		/* udp checksum */
298*58a2b000SEvgeniy Ivanov 		/* RPC reply header: */
299*58a2b000SEvgeniy Ivanov 		struct rpc_reply rpc;
300*58a2b000SEvgeniy Ivanov 	} *hhdr;
301*58a2b000SEvgeniy Ivanov 
302*58a2b000SEvgeniy Ivanov 	hhdr = ((struct hackhdr *)pkt) - 1;
303*58a2b000SEvgeniy Ivanov 	addr->s_addr = hhdr->ip_src;
304*58a2b000SEvgeniy Ivanov 	*port = hhdr->uh_sport;
305*58a2b000SEvgeniy Ivanov }
306*58a2b000SEvgeniy Ivanov 
307*58a2b000SEvgeniy Ivanov #ifdef NO_PMAP_CACHE
308*58a2b000SEvgeniy Ivanov #define rpc_pmap_getcache(addr, prog, vers) (-1)
309*58a2b000SEvgeniy Ivanov #define rpc_pmap_putcache(addr, prog, vers, port)
310*58a2b000SEvgeniy Ivanov #else
311*58a2b000SEvgeniy Ivanov 
312*58a2b000SEvgeniy Ivanov /*
313*58a2b000SEvgeniy Ivanov  * RPC Portmapper cache
314*58a2b000SEvgeniy Ivanov  */
315*58a2b000SEvgeniy Ivanov #define PMAP_NUM 8			/* need at most 5 pmap entries */
316*58a2b000SEvgeniy Ivanov 
317*58a2b000SEvgeniy Ivanov int rpc_pmap_num;
318*58a2b000SEvgeniy Ivanov struct pmap_list {
319*58a2b000SEvgeniy Ivanov 	struct in_addr	addr;	/* server, net order */
320*58a2b000SEvgeniy Ivanov 	u_int	prog;		/* host order */
321*58a2b000SEvgeniy Ivanov 	u_int	vers;		/* host order */
322*58a2b000SEvgeniy Ivanov 	int 	port;		/* host order */
323*58a2b000SEvgeniy Ivanov } rpc_pmap_list[PMAP_NUM];
324*58a2b000SEvgeniy Ivanov 
325*58a2b000SEvgeniy Ivanov /*
326*58a2b000SEvgeniy Ivanov  * return port number in host order, or -1.
327*58a2b000SEvgeniy Ivanov  * arguments are:
328*58a2b000SEvgeniy Ivanov  *  addr .. server, net order.
329*58a2b000SEvgeniy Ivanov  *  prog .. host order.
330*58a2b000SEvgeniy Ivanov  *  vers .. host order.
331*58a2b000SEvgeniy Ivanov  */
332*58a2b000SEvgeniy Ivanov int
rpc_pmap_getcache(struct in_addr addr,u_int prog,u_int vers)333*58a2b000SEvgeniy Ivanov rpc_pmap_getcache(struct in_addr addr, u_int prog, u_int vers)
334*58a2b000SEvgeniy Ivanov {
335*58a2b000SEvgeniy Ivanov 	struct pmap_list *pl;
336*58a2b000SEvgeniy Ivanov 
337*58a2b000SEvgeniy Ivanov 	for (pl = rpc_pmap_list; pl < &rpc_pmap_list[rpc_pmap_num]; pl++) {
338*58a2b000SEvgeniy Ivanov 		if (pl->addr.s_addr == addr.s_addr &&
339*58a2b000SEvgeniy Ivanov 			pl->prog == prog && pl->vers == vers )
340*58a2b000SEvgeniy Ivanov 		{
341*58a2b000SEvgeniy Ivanov 			return pl->port;
342*58a2b000SEvgeniy Ivanov 		}
343*58a2b000SEvgeniy Ivanov 	}
344*58a2b000SEvgeniy Ivanov 	return -1;
345*58a2b000SEvgeniy Ivanov }
346*58a2b000SEvgeniy Ivanov 
347*58a2b000SEvgeniy Ivanov /*
348*58a2b000SEvgeniy Ivanov  * arguments are:
349*58a2b000SEvgeniy Ivanov  *  addr .. server, net order.
350*58a2b000SEvgeniy Ivanov  *  prog .. host order.
351*58a2b000SEvgeniy Ivanov  *  vers .. host order.
352*58a2b000SEvgeniy Ivanov  *  port .. host order.
353*58a2b000SEvgeniy Ivanov  */
354*58a2b000SEvgeniy Ivanov void
rpc_pmap_putcache(struct in_addr addr,u_int prog,u_int vers,int port)355*58a2b000SEvgeniy Ivanov rpc_pmap_putcache(struct in_addr addr, u_int prog, u_int vers, int port)
356*58a2b000SEvgeniy Ivanov {
357*58a2b000SEvgeniy Ivanov 	struct pmap_list *pl;
358*58a2b000SEvgeniy Ivanov 
359*58a2b000SEvgeniy Ivanov 	/* Don't overflow cache... */
360*58a2b000SEvgeniy Ivanov 	if (rpc_pmap_num >= PMAP_NUM) {
361*58a2b000SEvgeniy Ivanov 		/* ... just re-use the last entry. */
362*58a2b000SEvgeniy Ivanov 		rpc_pmap_num = PMAP_NUM - 1;
363*58a2b000SEvgeniy Ivanov #ifdef	RPC_DEBUG
364*58a2b000SEvgeniy Ivanov 		printf("rpc_pmap_putcache: cache overflow\n");
365*58a2b000SEvgeniy Ivanov #endif
366*58a2b000SEvgeniy Ivanov 	}
367*58a2b000SEvgeniy Ivanov 
368*58a2b000SEvgeniy Ivanov 	pl = &rpc_pmap_list[rpc_pmap_num];
369*58a2b000SEvgeniy Ivanov 	rpc_pmap_num++;
370*58a2b000SEvgeniy Ivanov 
371*58a2b000SEvgeniy Ivanov 	/* Cache answer */
372*58a2b000SEvgeniy Ivanov 	pl->addr = addr;
373*58a2b000SEvgeniy Ivanov 	pl->prog = prog;
374*58a2b000SEvgeniy Ivanov 	pl->vers = vers;
375*58a2b000SEvgeniy Ivanov 	pl->port = port;
376*58a2b000SEvgeniy Ivanov }
377*58a2b000SEvgeniy Ivanov #endif
378*58a2b000SEvgeniy Ivanov 
379*58a2b000SEvgeniy Ivanov /*
380*58a2b000SEvgeniy Ivanov  * Request a port number from the port mapper.
381*58a2b000SEvgeniy Ivanov  * Returns the port in host order.
382*58a2b000SEvgeniy Ivanov  * prog and vers are host order.
383*58a2b000SEvgeniy Ivanov  */
384*58a2b000SEvgeniy Ivanov int
rpc_getport(struct iodesc * d,n_long prog,n_long vers)385*58a2b000SEvgeniy Ivanov rpc_getport(struct iodesc *d, n_long prog, n_long vers)
386*58a2b000SEvgeniy Ivanov {
387*58a2b000SEvgeniy Ivanov 	struct args {
388*58a2b000SEvgeniy Ivanov 		n_long	prog;		/* call program */
389*58a2b000SEvgeniy Ivanov 		n_long	vers;		/* call version */
390*58a2b000SEvgeniy Ivanov 		n_long	proto;		/* call protocol */
391*58a2b000SEvgeniy Ivanov 		n_long	port;		/* call port (unused) */
392*58a2b000SEvgeniy Ivanov 	} *args;
393*58a2b000SEvgeniy Ivanov 	struct res {
394*58a2b000SEvgeniy Ivanov 		n_long port;
395*58a2b000SEvgeniy Ivanov 	} *res;
396*58a2b000SEvgeniy Ivanov 	struct {
397*58a2b000SEvgeniy Ivanov 		n_long	h[RPC_HEADER_WORDS];
398*58a2b000SEvgeniy Ivanov 		struct args d;
399*58a2b000SEvgeniy Ivanov 	} sdata;
400*58a2b000SEvgeniy Ivanov 	struct {
401*58a2b000SEvgeniy Ivanov 		n_long	h[RPC_HEADER_WORDS];
402*58a2b000SEvgeniy Ivanov 		struct res d;
403*58a2b000SEvgeniy Ivanov 		n_long  pad;
404*58a2b000SEvgeniy Ivanov 	} rdata;
405*58a2b000SEvgeniy Ivanov 	ssize_t cc;
406*58a2b000SEvgeniy Ivanov 	int port;
407*58a2b000SEvgeniy Ivanov 
408*58a2b000SEvgeniy Ivanov #ifdef RPC_DEBUG
409*58a2b000SEvgeniy Ivanov 	if (debug)
410*58a2b000SEvgeniy Ivanov 		printf("getport: prog=0x%x vers=%d\n", prog, vers);
411*58a2b000SEvgeniy Ivanov #endif
412*58a2b000SEvgeniy Ivanov 
413*58a2b000SEvgeniy Ivanov 	/* This one is fixed forever. */
414*58a2b000SEvgeniy Ivanov 	if (prog == PMAPPROG)
415*58a2b000SEvgeniy Ivanov 		return PMAPPORT;
416*58a2b000SEvgeniy Ivanov 
417*58a2b000SEvgeniy Ivanov 	/* Try for cached answer first */
418*58a2b000SEvgeniy Ivanov 	port = rpc_pmap_getcache(d->destip, prog, vers);
419*58a2b000SEvgeniy Ivanov 	if (port != -1)
420*58a2b000SEvgeniy Ivanov 		return port;
421*58a2b000SEvgeniy Ivanov 
422*58a2b000SEvgeniy Ivanov 	args = &sdata.d;
423*58a2b000SEvgeniy Ivanov 	args->prog = htonl(prog);
424*58a2b000SEvgeniy Ivanov 	args->vers = htonl(vers);
425*58a2b000SEvgeniy Ivanov 	args->proto = htonl(IPPROTO_UDP);
426*58a2b000SEvgeniy Ivanov 	args->port = 0;
427*58a2b000SEvgeniy Ivanov 	res = &rdata.d;
428*58a2b000SEvgeniy Ivanov 
429*58a2b000SEvgeniy Ivanov 	cc = rpc_call(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
430*58a2b000SEvgeniy Ivanov 		args, sizeof(*args), res, sizeof(*res));
431*58a2b000SEvgeniy Ivanov 	if ((size_t)cc < sizeof(*res)) {
432*58a2b000SEvgeniy Ivanov 		printf("getport: %s", strerror(errno));
433*58a2b000SEvgeniy Ivanov 		errno = EBADRPC;
434*58a2b000SEvgeniy Ivanov 		return -1;
435*58a2b000SEvgeniy Ivanov 	}
436*58a2b000SEvgeniy Ivanov 	port = (int)ntohl(res->port);
437*58a2b000SEvgeniy Ivanov 
438*58a2b000SEvgeniy Ivanov 	rpc_pmap_putcache(d->destip, prog, vers, port);
439*58a2b000SEvgeniy Ivanov 
440*58a2b000SEvgeniy Ivanov 	return port;
441*58a2b000SEvgeniy Ivanov }
442