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