|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ ! 23: /* ! 24: * Copyright (c) 1994 Gordon Ross, Adam Glass ! 25: * Copyright (c) 1992 Regents of the University of California. ! 26: * All rights reserved. ! 27: * ! 28: * This software was developed by the Computer Systems Engineering group ! 29: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and ! 30: * contributed to Berkeley. ! 31: * ! 32: * Redistribution and use in source and binary forms, with or without ! 33: * modification, are permitted provided that the following conditions ! 34: * are met: ! 35: * 1. Redistributions of source code must retain the above copyright ! 36: * notice, this list of conditions and the following disclaimer. ! 37: * 2. Redistributions in binary form must reproduce the above copyright ! 38: * notice, this list of conditions and the following disclaimer in the ! 39: * documentation and/or other materials provided with the distribution. ! 40: * 3. All advertising materials mentioning features or use of this software ! 41: * must display the following acknowledgement: ! 42: * This product includes software developed by the University of ! 43: * California, Lawrence Berkeley Laboratory and its contributors. ! 44: * 4. Neither the name of the University nor the names of its contributors ! 45: * may be used to endorse or promote products derived from this software ! 46: * without specific prior written permission. ! 47: * ! 48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 58: * SUCH DAMAGE. ! 59: * ! 60: */ ! 61: ! 62: #include <sys/param.h> ! 63: #include <sys/conf.h> ! 64: #include <sys/ioctl.h> ! 65: #include <sys/proc.h> ! 66: #include <sys/mount.h> ! 67: #include <sys/mbuf.h> ! 68: #include <sys/malloc.h> ! 69: #include <sys/socket.h> ! 70: #include <sys/socketvar.h> ! 71: #include <sys/systm.h> ! 72: #include <sys/reboot.h> ! 73: ! 74: #include <net/if.h> ! 75: #include <netinet/in.h> ! 76: ! 77: #include <nfs/rpcv2.h> ! 78: #include <nfs/krpc.h> ! 79: ! 80: /* ! 81: * Kernel support for Sun RPC ! 82: * ! 83: * Used currently for bootstrapping in nfs diskless configurations. ! 84: * ! 85: * Note: will not work on variable-sized rpc args/results. ! 86: * implicit size-limit of an mbuf. ! 87: */ ! 88: ! 89: /* ! 90: * Generic RPC headers ! 91: */ ! 92: ! 93: struct auth_info { ! 94: u_int32_t rp_atype; /* auth type */ ! 95: u_int32_t rp_alen; /* auth length */ ! 96: }; ! 97: ! 98: struct rpc_call { ! 99: u_int32_t rp_xid; /* request transaction id */ ! 100: int32_t rp_direction; /* call direction (0) */ ! 101: u_int32_t rp_rpcvers; /* rpc version (2) */ ! 102: u_int32_t rp_prog; /* program */ ! 103: u_int32_t rp_vers; /* version */ ! 104: u_int32_t rp_proc; /* procedure */ ! 105: struct auth_info rp_auth; ! 106: struct auth_info rp_verf; ! 107: }; ! 108: ! 109: struct rpc_reply { ! 110: u_int32_t rp_xid; /* request transaction id */ ! 111: int32_t rp_direction; /* call direction (1) */ ! 112: int32_t rp_astatus; /* accept status (0: accepted) */ ! 113: union { ! 114: u_int32_t rpu_errno; ! 115: struct { ! 116: struct auth_info rp_auth; ! 117: u_int32_t rp_rstatus; ! 118: } rpu_ok; ! 119: } rp_u; ! 120: }; ! 121: ! 122: #define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ ! 123: ! 124: /* ! 125: * What is the longest we will wait before re-sending a request? ! 126: * Note this is also the frequency of "RPC timeout" messages. ! 127: * The re-send loop count sup linearly to this maximum, so the ! 128: * first complaint will happen after (1+2+3+4+5)=15 seconds. ! 129: */ ! 130: #define MAX_RESEND_DELAY 5 /* seconds */ ! 131: ! 132: /* ! 133: * Call portmap to lookup a port number for a particular rpc program ! 134: * Returns non-zero error on failure. ! 135: */ ! 136: int ! 137: krpc_portmap(sin, prog, vers, portp) ! 138: struct sockaddr_in *sin; /* server address */ ! 139: u_int prog, vers; /* host order */ ! 140: u_int16_t *portp; /* network order */ ! 141: { ! 142: struct sdata { ! 143: u_int32_t prog; /* call program */ ! 144: u_int32_t vers; /* call version */ ! 145: u_int32_t proto; /* call protocol */ ! 146: u_int32_t port; /* call port (unused) */ ! 147: } *sdata; ! 148: struct rdata { ! 149: u_int16_t pad; ! 150: u_int16_t port; ! 151: } *rdata; ! 152: struct mbuf *m; ! 153: int error; ! 154: ! 155: /* The portmapper port is fixed. */ ! 156: if (prog == PMAPPROG) { ! 157: *portp = htons(PMAPPORT); ! 158: return 0; ! 159: } ! 160: ! 161: m = m_gethdr(M_WAIT, MT_DATA); ! 162: if (m == NULL) ! 163: return ENOBUFS; ! 164: m->m_len = sizeof(*sdata); ! 165: m->m_pkthdr.len = m->m_len; ! 166: sdata = mtod(m, struct sdata *); ! 167: ! 168: /* Do the RPC to get it. */ ! 169: sdata->prog = htonl(prog); ! 170: sdata->vers = htonl(vers); ! 171: sdata->proto = htonl(IPPROTO_UDP); ! 172: sdata->port = 0; ! 173: ! 174: sin->sin_port = htons(PMAPPORT); ! 175: error = krpc_call(sin, PMAPPROG, PMAPVERS, ! 176: PMAPPROC_GETPORT, &m, NULL); ! 177: if (error) ! 178: return error; ! 179: ! 180: rdata = mtod(m, struct rdata *); ! 181: *portp = rdata->port; ! 182: ! 183: m_freem(m); ! 184: return 0; ! 185: } ! 186: ! 187: /* ! 188: * Do a remote procedure call (RPC) and wait for its reply. ! 189: * If from_p is non-null, then we are doing broadcast, and ! 190: * the address from whence the response came is saved there. ! 191: */ ! 192: int ! 193: krpc_call(sa, prog, vers, func, data, from_p) ! 194: struct sockaddr_in *sa; ! 195: u_int prog, vers, func; ! 196: struct mbuf **data; /* input/output */ ! 197: struct sockaddr_in **from_p; /* output */ ! 198: { ! 199: struct socket *so; ! 200: struct sockaddr_in *sin; ! 201: struct mbuf *m, *nam, *mhead, *mhck; ! 202: struct rpc_call *call; ! 203: struct rpc_reply *reply; ! 204: struct uio auio; ! 205: int error, rcvflg, timo, secs, len; ! 206: static u_int32_t xid = ~0xFF; ! 207: u_int16_t tport; ! 208: struct sockopt sopt; ! 209: ! 210: /* ! 211: * Validate address family. ! 212: * Sorry, this is INET specific... ! 213: */ ! 214: if (sa->sin_family != AF_INET) ! 215: return (EAFNOSUPPORT); ! 216: ! 217: /* Free at end if not null. */ ! 218: nam = mhead = NULL; ! 219: if (from_p) ! 220: *from_p = 0; ! 221: ! 222: /* ! 223: * Create socket and set its recieve timeout. ! 224: */ ! 225: if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0))) ! 226: goto out; ! 227: ! 228: { ! 229: struct timeval tv; ! 230: ! 231: tv.tv_sec = 1; ! 232: tv.tv_usec = 0; ! 233: bzero(&sopt, sizeof sopt); ! 234: sopt.sopt_level = SOL_SOCKET; ! 235: sopt.sopt_name = SO_RCVTIMEO; ! 236: sopt.sopt_val = &tv; ! 237: sopt.sopt_valsize = sizeof tv; ! 238: ! 239: if (error = sosetopt(so, &sopt)) ! 240: goto out; ! 241: ! 242: } ! 243: ! 244: /* ! 245: * Enable broadcast if necessary. ! 246: */ ! 247: ! 248: if (from_p) { ! 249: int on = 1; ! 250: sopt.sopt_name = SO_BROADCAST; ! 251: sopt.sopt_val = &on; ! 252: sopt.sopt_valsize = sizeof on; ! 253: if (error = sosetopt(so, &sopt)) ! 254: goto out; ! 255: } ! 256: ! 257: /* ! 258: * Bind the local endpoint to a reserved port, ! 259: * because some NFS servers refuse requests from ! 260: * non-reserved (non-privileged) ports. ! 261: */ ! 262: m = m_getclr(M_WAIT, MT_SONAME); ! 263: sin = mtod(m, struct sockaddr_in *); ! 264: sin->sin_len = m->m_len = sizeof(*sin); ! 265: sin->sin_family = AF_INET; ! 266: sin->sin_addr.s_addr = INADDR_ANY; ! 267: tport = IPPORT_RESERVED; ! 268: do { ! 269: tport--; ! 270: sin->sin_port = htons(tport); ! 271: error = sobind(so, mtod(m, struct sockaddr *)); ! 272: } while (error == EADDRINUSE && ! 273: tport > IPPORT_RESERVED / 2); ! 274: m_freem(m); ! 275: if (error) { ! 276: printf("bind failed\n"); ! 277: goto out; ! 278: } ! 279: ! 280: /* ! 281: * Setup socket address for the server. ! 282: */ ! 283: nam = m_get(M_WAIT, MT_SONAME); ! 284: if (nam == NULL) { ! 285: error = ENOBUFS; ! 286: goto out; ! 287: } ! 288: sin = mtod(nam, struct sockaddr_in *); ! 289: bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sin_len)); ! 290: ! 291: /* ! 292: * Prepend RPC message header. ! 293: */ ! 294: m = *data; ! 295: *data = NULL; ! 296: #if DIAGNOSTIC ! 297: if ((m->m_flags & M_PKTHDR) == 0) ! 298: panic("krpc_call: send data w/o pkthdr"); ! 299: if (m->m_pkthdr.len < m->m_len) ! 300: panic("krpc_call: pkthdr.len not set"); ! 301: #endif ! 302: mhead = m_prepend(m, sizeof(*call), M_WAIT); ! 303: if (mhead == NULL) { ! 304: error = ENOBUFS; ! 305: goto out; ! 306: } ! 307: mhead->m_pkthdr.len += sizeof(*call); ! 308: mhead->m_pkthdr.rcvif = NULL; ! 309: ! 310: /* ! 311: * Fill in the RPC header ! 312: */ ! 313: call = mtod(mhead, struct rpc_call *); ! 314: bzero((caddr_t)call, sizeof(*call)); ! 315: xid++; ! 316: call->rp_xid = htonl(xid); ! 317: /* call->rp_direction = 0; */ ! 318: call->rp_rpcvers = htonl(2); ! 319: call->rp_prog = htonl(prog); ! 320: call->rp_vers = htonl(vers); ! 321: call->rp_proc = htonl(func); ! 322: /* call->rp_auth = 0; */ ! 323: /* call->rp_verf = 0; */ ! 324: ! 325: /* ! 326: * Send it, repeatedly, until a reply is received, ! 327: * but delay each re-send by an increasing amount. ! 328: * If the delay hits the maximum, start complaining. ! 329: */ ! 330: timo = 0; ! 331: for (;;) { ! 332: /* Send RPC request (or re-send). */ ! 333: m = m_copym(mhead, 0, M_COPYALL, M_WAIT); ! 334: if (m == NULL) { ! 335: error = ENOBUFS; ! 336: goto out; ! 337: } ! 338: error = sosend(so, mtod(nam, struct sockaddr *), NULL, m, NULL, 0); ! 339: if (error) { ! 340: printf("krpc_call: sosend: %d\n", error); ! 341: goto out; ! 342: } ! 343: m = NULL; ! 344: ! 345: /* Determine new timeout. */ ! 346: if (timo < MAX_RESEND_DELAY) ! 347: timo++; ! 348: else ! 349: printf("RPC timeout for server 0x%x\n", ! 350: ntohl(sin->sin_addr.s_addr)); ! 351: ! 352: /* ! 353: * Wait for up to timo seconds for a reply. ! 354: * The socket receive timeout was set to 1 second. ! 355: */ ! 356: secs = timo; ! 357: while (secs > 0) { ! 358: if ((from_p) && (*from_p)){ ! 359: FREE(*from_p, M_SONAME); ! 360: *from_p = NULL; ! 361: } ! 362: ! 363: if (m) { ! 364: m_freem(m); ! 365: m = NULL; ! 366: } ! 367: auio.uio_resid = len = 1<<16; ! 368: rcvflg = 0; ! 369: ! 370: error = soreceive(so, (struct sockaddr **) from_p, &auio, &m, NULL, &rcvflg); ! 371: ! 372: if (error == EWOULDBLOCK) { ! 373: secs--; ! 374: continue; ! 375: } ! 376: if (error) ! 377: goto out; ! 378: len -= auio.uio_resid; ! 379: ! 380: /* Does the reply contain at least a header? */ ! 381: if (len < MIN_REPLY_HDR) ! 382: continue; ! 383: if (m->m_len < MIN_REPLY_HDR) ! 384: continue; ! 385: reply = mtod(m, struct rpc_reply *); ! 386: ! 387: /* Is it the right reply? */ ! 388: if (reply->rp_direction != htonl(RPC_REPLY)) ! 389: continue; ! 390: ! 391: if (reply->rp_xid != htonl(xid)) ! 392: continue; ! 393: ! 394: /* Was RPC accepted? (authorization OK) */ ! 395: if (reply->rp_astatus != 0) { ! 396: error = ntohl(reply->rp_u.rpu_errno); ! 397: printf("rpc denied, error=%d\n", error); ! 398: continue; ! 399: } ! 400: ! 401: /* Did the call succeed? */ ! 402: if ((error = ntohl(reply->rp_u.rpu_ok.rp_rstatus)) != 0) { ! 403: printf("rpc status=%d\n", error); ! 404: continue; ! 405: } ! 406: ! 407: goto gotreply; /* break two levels */ ! 408: ! 409: } /* while secs */ ! 410: } /* forever send/receive */ ! 411: ! 412: error = ETIMEDOUT; ! 413: goto out; ! 414: ! 415: gotreply: ! 416: ! 417: /* ! 418: * Pull as much as we can into first mbuf, to make ! 419: * result buffer contiguous. Note that if the entire ! 420: * result won't fit into one mbuf, you're out of luck. ! 421: * XXX - Should not rely on making the entire reply ! 422: * contiguous (fix callers instead). -gwr ! 423: */ ! 424: #if DIAGNOSTIC ! 425: if ((m->m_flags & M_PKTHDR) == 0) ! 426: panic("krpc_call: received pkt w/o header?"); ! 427: #endif ! 428: len = m->m_pkthdr.len; ! 429: if (m->m_len < len) { ! 430: m = m_pullup(m, len); ! 431: if (m == NULL) { ! 432: error = ENOBUFS; ! 433: goto out; ! 434: } ! 435: reply = mtod(m, struct rpc_reply *); ! 436: } ! 437: ! 438: /* ! 439: * Strip RPC header ! 440: */ ! 441: len = sizeof(*reply); ! 442: if (reply->rp_u.rpu_ok.rp_auth.rp_atype != 0) { ! 443: len += ntohl(reply->rp_u.rpu_ok.rp_auth.rp_alen); ! 444: len = (len + 3) & ~3; /* XXX? */ ! 445: } ! 446: m_adj(m, len); ! 447: ! 448: /* result */ ! 449: *data = m; ! 450: out: ! 451: if (nam) m_freem(nam); ! 452: if (mhead) m_freem(mhead); ! 453: soclose(so); ! 454: return error; ! 455: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.