|
|
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.