1 /* 2 * Copyright (c) 1994 Gordon Ross, Adam Glass 3 * Copyright (c) 1992 Regents of the University of California. 4 * All rights reserved. 5 * 6 * This software was developed by the Computer Systems Engineering group 7 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 8 * contributed to Berkeley. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Lawrence Berkeley Laboratory and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * partially based on: 39 * libnetboot/rpc.c 40 * @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL) 41 * $Id: krpc_subr.c,v 1.2 1994/06/13 15:28:55 gwr Exp $ 42 */ 43 44 #include <sys/param.h> 45 #include <sys/conf.h> 46 #include <sys/ioctl.h> 47 #include <sys/proc.h> 48 #include <sys/mount.h> 49 #include <sys/mbuf.h> 50 #include <sys/socket.h> 51 #include <sys/systm.h> 52 #include <sys/reboot.h> 53 54 #include <net/if.h> 55 #include <netinet/in.h> 56 57 #include <nfs/rpcv2.h> 58 59 /* 60 * Kernel support for Sun RPC 61 * 62 * Used currently for bootstrapping in nfs diskless configurations. 63 * 64 * Note: will not work on variable-sized rpc args/results. 65 * implicit size-limit of an mbuf. 66 */ 67 68 #define PMAPPORT 111 69 #define PMAPPROG 100000 70 #define PMAPVERS 2 71 #define PMAPPROC_GETPORT 3 72 73 /* 74 * Generic RPC headers 75 */ 76 77 struct auth_info { 78 int rp_atype; /* auth type */ 79 u_long rp_alen; /* auth length */ 80 }; 81 82 struct rpc_call { 83 u_long rp_xid; /* request transaction id */ 84 int rp_direction; /* call direction (0) */ 85 u_long rp_rpcvers; /* rpc version (2) */ 86 u_long rp_prog; /* program */ 87 u_long rp_vers; /* version */ 88 u_long rp_proc; /* procedure */ 89 struct auth_info rp_auth; 90 struct auth_info rp_verf; 91 }; 92 93 struct rpc_reply { 94 u_long rp_xid; /* request transaction id */ 95 int rp_direction; /* call direction (1) */ 96 int rp_astatus; /* accept status (0: accepted) */ 97 union { 98 u_long rpu_errno; 99 struct { 100 struct auth_info rp_auth; 101 u_long rp_rstatus; /* reply status */ 102 } rpu_ok; 103 } rp_u; 104 }; 105 106 #define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ 107 108 /* 109 * What is the longest we will wait before re-sending a request? 110 * Note this is also the frequency of "RPC timeout" messages. 111 * The re-send loop count sup linearly to this maximum, so the 112 * first complaint will happen after (1+2+3+4+5)=15 seconds. 113 */ 114 #define MAX_RESEND_DELAY 5 /* seconds */ 115 116 /* 117 * Call portmap to lookup a port number for a particular rpc program 118 * Returns non-zero error on failure. 119 */ 120 int 121 krpc_portmap(sa, prog, vers, portp) 122 struct sockaddr *sa; /* server address */ 123 u_long prog, vers; /* host order */ 124 u_short *portp; /* network order */ 125 { 126 struct sdata { 127 u_long prog; /* call program */ 128 u_long vers; /* call version */ 129 u_long proto; /* call protocol */ 130 u_long port; /* call port (unused) */ 131 } *sdata; 132 struct rdata { 133 u_short pad; 134 u_short port; 135 } *rdata; 136 struct mbuf *m; 137 int error; 138 139 /* The portmapper port is fixed. */ 140 if (prog == PMAPPROG) { 141 *portp = htons(PMAPPORT); 142 return 0; 143 } 144 145 m = m_gethdr(M_WAIT, MT_DATA); 146 if (m == NULL) 147 return ENOBUFS; 148 m->m_len = sizeof(*sdata); 149 m->m_pkthdr.len = m->m_len; 150 sdata = mtod(m, struct sdata *); 151 152 /* Do the RPC to get it. */ 153 sdata->prog = htonl(prog); 154 sdata->vers = htonl(vers); 155 sdata->proto = htonl(IPPROTO_UDP); 156 sdata->port = 0; 157 158 error = krpc_call(sa, PMAPPROG, PMAPVERS, 159 PMAPPROC_GETPORT, &m); 160 if (error) 161 return error; 162 163 rdata = mtod(m, struct rdata *); 164 *portp = rdata->port; 165 166 m_freem(m); 167 return 0; 168 } 169 170 /* 171 * Do a remote procedure call (RPC) and wait for its reply. 172 */ 173 int 174 krpc_call(sa, prog, vers, func, data) 175 struct sockaddr *sa; 176 u_long prog, vers, func; 177 struct mbuf **data; /* input/output */ 178 { 179 struct socket *so; 180 struct sockaddr_in *sin; 181 struct timeval *tv; 182 struct mbuf *m, *nam, *mhead; 183 struct rpc_call *call; 184 struct rpc_reply *reply; 185 struct uio auio; 186 int error, rcvflg, timo, secs, len; 187 static u_long xid = ~0xFF; 188 189 /* 190 * Validate address family. 191 * Sorry, this is INET specific... 192 */ 193 if (sa->sa_family != AF_INET) 194 return (EAFNOSUPPORT); 195 196 /* Free at end if not null. */ 197 nam = mhead = NULL; 198 199 /* 200 * Create socket and set its recieve timeout. 201 */ 202 if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0))) 203 goto out; 204 205 m = m_get(M_WAIT, MT_SOOPTS); 206 if (m == NULL) { 207 error = ENOBUFS; 208 goto out; 209 } 210 tv = mtod(m, struct timeval *); 211 m->m_len = sizeof(*tv); 212 tv->tv_sec = 1; 213 tv->tv_usec = 0; 214 if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m))) 215 goto out; 216 217 /* 218 * Setup socket address for the server. 219 */ 220 nam = m_get(M_WAIT, MT_SONAME); 221 if (nam == NULL) { 222 error = ENOBUFS; 223 goto out; 224 } 225 sin = mtod(nam, struct sockaddr_in *); 226 bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sa_len)); 227 228 /* 229 * Set the port number that the request will use. 230 */ 231 if ((error = krpc_portmap(sa, prog, vers, &sin->sin_port))) 232 goto out; 233 234 /* 235 * Prepend RPC message header. 236 */ 237 m = *data; 238 *data = NULL; 239 #ifdef DIAGNOSTIC 240 if ((m->m_flags & M_PKTHDR) == 0) 241 panic("krpc_call: send data w/o pkthdr"); 242 if (m->m_pkthdr.len < m->m_len) 243 panic("krpc_call: pkthdr.len not set"); 244 #endif 245 mhead = m_prepend(m, sizeof(*call), M_WAIT); 246 if (mhead == NULL) { 247 error = ENOBUFS; 248 goto out; 249 } 250 mhead->m_pkthdr.len += sizeof(*call); 251 mhead->m_pkthdr.rcvif = NULL; 252 253 /* 254 * Fill in the RPC header 255 */ 256 call = mtod(mhead, struct rpc_call *); 257 bzero((caddr_t)call, sizeof(*call)); 258 call->rp_xid = ++xid; /* no need to put in network order */ 259 /* call->rp_direction = 0; */ 260 call->rp_rpcvers = htonl(2); 261 call->rp_prog = htonl(prog); 262 call->rp_vers = htonl(vers); 263 call->rp_proc = htonl(func); 264 /* call->rp_auth = 0; */ 265 /* call->rp_verf = 0; */ 266 267 /* 268 * Send it, repeatedly, until a reply is received, 269 * but delay each re-send by an increasing amount. 270 * If the delay hits the maximum, start complaining. 271 */ 272 timo = 0; 273 for (;;) { 274 /* Send RPC request (or re-send). */ 275 m = m_copym(mhead, 0, M_COPYALL, M_WAIT); 276 if (m == NULL) { 277 error = ENOBUFS; 278 goto out; 279 } 280 error = sosend(so, nam, NULL, m, NULL, 0); 281 if (error) { 282 printf("krpc_call: sosend: %d\n", error); 283 goto out; 284 } 285 m = NULL; 286 287 /* Determine new timeout. */ 288 if (timo < MAX_RESEND_DELAY) 289 timo++; 290 else 291 printf("RPC timeout for server 0x%x\n", 292 ntohl(sin->sin_addr.s_addr)); 293 294 /* 295 * Wait for up to timo seconds for a reply. 296 * The socket receive timeout was set to 1 second. 297 */ 298 secs = timo; 299 while (secs > 0) { 300 auio.uio_resid = len = 1<<16; 301 rcvflg = 0; 302 error = soreceive(so, NULL, &auio, &m, NULL, &rcvflg); 303 if (error == EWOULDBLOCK) { 304 secs--; 305 continue; 306 } 307 if (error) 308 goto out; 309 len -= auio.uio_resid; 310 311 /* Is the reply complete and the right one? */ 312 if (len < MIN_REPLY_HDR) { 313 m_freem(m); 314 continue; 315 } 316 if (m->m_len < MIN_REPLY_HDR) { 317 m = m_pullup(m, MIN_REPLY_HDR); 318 if (!m) 319 continue; 320 } 321 reply = mtod(m, struct rpc_reply *); 322 if ((reply->rp_direction == htonl(RPC_REPLY)) && 323 (reply->rp_xid == xid)) 324 goto gotreply; /* break two levels */ 325 } /* while secs */ 326 } /* forever send/receive */ 327 gotreply: 328 329 /* 330 * Make result buffer contiguous. 331 */ 332 #ifdef DIAGNOSTIC 333 if ((m->m_flags & M_PKTHDR) == 0) 334 panic("krpc_call: received pkt w/o header?"); 335 #endif 336 len = m->m_pkthdr.len; 337 if (m->m_len < len) { 338 m = m_pullup(m, len); 339 if (m == NULL) { 340 error = ENOBUFS; 341 goto out; 342 } 343 } 344 reply = mtod(m, struct rpc_reply *); 345 346 /* 347 * Check RPC acceptance and status. 348 */ 349 if (reply->rp_astatus != 0) { 350 error = reply->rp_u.rpu_errno; 351 printf("rpc denied, error=%d\n", error); 352 m_freem(m); 353 goto out; 354 } 355 if ((error = reply->rp_u.rpu_ok.rp_rstatus) != 0) { 356 printf("rpc status=%d\n", error); 357 m_freem(m); 358 goto out; 359 } 360 361 /* 362 * Strip RPC header 363 */ 364 len = sizeof(*reply); 365 if (reply->rp_u.rpu_ok.rp_auth.rp_atype != 0) { 366 len += ntohl(reply->rp_u.rpu_ok.rp_auth.rp_alen); 367 len = (len + 3) & ~3; /* XXX? */ 368 } 369 m_adj(m, len); 370 371 /* result */ 372 *data = m; 373 374 out: 375 if (nam) m_freem(nam); 376 if (mhead) m_freem(mhead); 377 soclose(so); 378 return error; 379 } 380