1 /* $NetBSD: rpc.c,v 1.4 1995/02/20 11:04:18 mycroft 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 #include <nfs/xdr_subs.h> 51 52 #include <string.h> 53 54 #include "stand.h" 55 #include "net.h" 56 #include "netif.h" 57 #include "rpc.h" 58 59 /* XXX Data part of nfs rpc reply (also the largest thing we receive) */ 60 struct nfs_reply_data { 61 u_long errno; 62 u_char fa[NFSX_FATTR(0)]; 63 u_long count; 64 u_char data[1200]; 65 }; 66 #define NFSREAD_SIZE sizeof(((struct nfs_reply_data *)0)->data) 67 68 /* Cache stuff */ 69 #define PMAP_NUM 8 /* need at most 5 pmap entries */ 70 71 static struct pmap_list { 72 u_long addr; /* address of server */ 73 u_long prog; 74 u_long vers; 75 u_short port; /* cached port for service */ 76 } pmap_list[PMAP_NUM] = { 77 { 0, PMAPPROG, PMAPVERS, PMAPPORT } 78 }; 79 static int pmap_num = 1; 80 81 /* Local forwards */ 82 static size_t recvrpc __P((struct iodesc *, void *, size_t, time_t)); 83 84 /* Make a rpc call; return length of answer */ 85 size_t 86 callrpc(d, prog, vers, proc, sdata, slen, rdata, rlen) 87 register struct iodesc *d; 88 register u_long prog, vers, proc; 89 register void *sdata; 90 register size_t slen; 91 register void *rdata; 92 register size_t rlen; 93 { 94 register size_t cc; 95 register u_long *tl; 96 struct { 97 u_char header[HEADER_SIZE]; 98 u_long data[96]; /* XXX */ 99 } wbuf; 100 struct { 101 u_char header[HEADER_SIZE]; 102 struct rpc_reply rrpc; 103 union { 104 u_long errno; 105 u_char data[sizeof(struct nfs_reply_data)]; 106 } ru; 107 } rbuf; 108 109 #ifdef RPC_DEBUG 110 if (debug) 111 printf("callrpc: called\n"); 112 #endif 113 if (rlen > sizeof(rbuf.ru.data)) 114 panic("callrpc: huge read (%d > %d)", 115 rlen, sizeof(rbuf.ru.data)); 116 117 d->destport = getport(d, prog, vers); 118 119 tl = wbuf.data; 120 121 /* Fill in RPC call structure. */ 122 *tl++ = txdr_unsigned(d->xid); 123 *tl++ = txdr_unsigned(RPC_CALL); 124 *tl++ = txdr_unsigned(RPC_VER2); 125 *tl++ = txdr_unsigned(prog); 126 *tl++ = txdr_unsigned(vers); 127 *tl++ = txdr_unsigned(proc); 128 129 /* Fill in authorization info. */ 130 if (prog != NFS_PROG) { 131 *tl++ = txdr_unsigned(RPCAUTH_NULL); 132 *tl++ = txdr_unsigned(0); 133 } else { 134 *tl++ = txdr_unsigned(RPCAUTH_UNIX); 135 *tl++ = txdr_unsigned(3*NFSX_UNSIGNED); 136 *tl++ = txdr_unsigned(0); /* time */ 137 *tl++ = txdr_unsigned(0); /* host name length */ 138 *tl++ = txdr_unsigned(0); /* uid */ 139 *tl++ = txdr_unsigned(0); /* gid */ 140 *tl++ = txdr_unsigned(0); /* gid list length */ 141 } 142 *tl++ = txdr_unsigned(RPCAUTH_NULL); 143 *tl++ = txdr_unsigned(0); 144 145 /* Fill in RPC call arguments. */ 146 bcopy(sdata, tl, slen); 147 148 cc = sendrecv(d, 149 sendudp, wbuf.data, 150 (tl - wbuf.data) * NFSX_UNSIGNED + slen, 151 recvrpc, &rbuf.rrpc, 152 sizeof(struct rpc_reply) + sizeof(struct nfs_reply_data)); 153 154 #ifdef RPC_DEBUG 155 if (debug) 156 printf("callrpc: cc=%d rlen=%d, rp_stat=%d\n", cc, rlen, 157 rbuf.rrpc.rp_stat); 158 #endif 159 160 /* Bump xid so next request will be unique. */ 161 ++d->xid; 162 163 if (cc == -1) 164 return (-1); 165 if (cc < rlen) { 166 /* Check for an error return */ 167 if (cc >= sizeof(rbuf.ru.errno) && rbuf.ru.errno != 0) { 168 errno = ntohl(rbuf.ru.errno); 169 return (-1); 170 } 171 panic("callrpc: missing data (%d < %d)", cc, rlen); 172 } 173 if (cc > sizeof(rbuf.ru.data)) 174 panic("callrpc: huge return (%d > %d)", 175 cc, sizeof(rbuf.ru.data)); 176 bcopy(rbuf.ru.data, rdata, cc); 177 return (cc); 178 } 179 180 /* Returns true if packet is the one we're waiting for */ 181 static size_t 182 recvrpc(d, pkt, len, tleft) 183 register struct iodesc *d; 184 register void *pkt; 185 register size_t len; 186 time_t tleft; 187 { 188 register struct rpc_reply *rpc; 189 190 errno = 0; 191 #ifdef RPC_DEBUG 192 if (debug) 193 printf("recvrpc: called len=%d\n", len); 194 #endif 195 196 len = readudp(d, pkt, len, tleft); 197 if (len == -1 || len < sizeof(struct rpc_reply)) 198 goto bad; 199 200 rpc = (struct rpc_reply *)pkt; 201 NTOHL(rpc->rp_xid); 202 NTOHL(rpc->rp_direction); 203 NTOHL(rpc->rp_stat); 204 205 if (rpc->rp_xid != d->xid || 206 rpc->rp_direction != RPC_REPLY || 207 rpc->rp_stat != RPC_MSGACCEPTED) { 208 #ifdef RPC_DEBUG 209 if (debug) { 210 if (rpc->rp_xid != d->xid) 211 printf("recvrpc: rp_xid %d != xid %d\n", 212 rpc->rp_xid, d->xid); 213 if (rpc->rp_direction != RPC_REPLY) 214 printf("recvrpc: rp_direction %d != RPC_REPLY\n", 215 rpc->rp_direction); 216 if (rpc->rp_stat != RPC_MSGACCEPTED) 217 printf("recvrpc: rp_stat %d != RPC_MSGACCEPTED\n", 218 rpc->rp_stat); 219 } 220 #endif 221 goto bad; 222 } 223 224 /* Return data count (thus indicating success) */ 225 return (len - sizeof(*rpc)); 226 227 bad: 228 return (-1); 229 } 230 231 /* Request a port number from the port mapper */ 232 u_short 233 getport(d, prog, vers) 234 register struct iodesc *d; 235 u_long prog; 236 u_long vers; 237 { 238 register int i; 239 register struct pmap_list *pl; 240 u_long port; 241 struct { 242 u_long prog; /* call program */ 243 u_long vers; /* call version */ 244 u_long proto; /* call protocol */ 245 u_long port; /* call port (unused) */ 246 } sdata; 247 248 #ifdef RPC_DEBUG 249 if (debug) 250 printf("getport: called\n"); 251 #endif 252 /* Try for cached answer first */ 253 for (i = 0, pl = pmap_list; i < pmap_num; ++i, ++pl) 254 if ((pl->addr == d->destip || pl->addr == 0) && 255 pl->prog == prog && pl->vers == vers) 256 return (pl->port); 257 258 /* Don't overflow cache */ 259 if (pmap_num > PMAP_NUM - 1) 260 panic("getport: overflowed pmap_list!"); 261 262 sdata.prog = htonl(prog); 263 sdata.vers = htonl(vers); 264 sdata.proto = htonl(IPPROTO_UDP); 265 sdata.port = 0; 266 267 if (callrpc(d, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, 268 &sdata, sizeof(sdata), &port, sizeof(port)) < 0) { 269 printf("getport: %s", strerror(errno)); 270 return(-1); 271 } 272 273 /* Cache answer */ 274 pl->addr = d->destip; 275 pl->prog = prog; 276 pl->vers = vers; 277 pl->port = port; 278 ++pmap_num; 279 280 return ((u_short)port); 281 } 282