Do the first BOOTPARAM RPC call to the broadcast address instead of

using the address of the RARP server because a BOOTPARAM server
might not be running on the machine that sent the RARP reply.
This commit is contained in:
gwr 1994-09-26 16:42:29 +00:00
parent 6b78d3957c
commit 62f18b1dda
3 changed files with 204 additions and 110 deletions

33
sys/nfs/krpc.h Normal file
View File

@ -0,0 +1,33 @@
#include <sys/cdefs.h>
int krpc_call __P((struct sockaddr_in *sin, \
u_long prog, u_long vers, u_long func, \
struct mbuf **data, struct mbuf **from));
int krpc_portmap __P((struct sockaddr_in *sin, \
u_long prog, u_long vers, u_short *portp));
/*
* RPC definitions for the portmapper
*/
#define PMAPPORT 111
#define PMAPPROG 100000
#define PMAPVERS 2
#define PMAPPROC_NULL 0
#define PMAPPROC_SET 1
#define PMAPPROC_UNSET 2
#define PMAPPROC_GETPORT 3
#define PMAPPROC_DUMP 4
#define PMAPPROC_CALLIT 5
/*
* RPC definitions for bootparamd
*/
#define BOOTPARAM_PROG 100026
#define BOOTPARAM_VERS 1
#define BOOTPARAM_WHOAMI 1
#define BOOTPARAM_GETFILE 2

View File

@ -1,4 +1,4 @@
/* $NetBSD: krpc_subr.c,v 1.6 1994/08/12 04:31:51 cgd Exp $ */
/* $NetBSD: krpc_subr.c,v 1.7 1994/09/26 16:42:31 gwr Exp $ */
/*
* Copyright (c) 1994 Gordon Ross, Adam Glass
@ -56,6 +56,7 @@
#include <netinet/in.h>
#include <nfs/rpcv2.h>
#include <nfs/krpc.h>
/*
* Kernel support for Sun RPC
@ -65,11 +66,6 @@
* Note: will not work on variable-sized rpc args/results.
* implicit size-limit of an mbuf.
*/
#define PMAPPORT 111
#define PMAPPROG 100000
#define PMAPVERS 2
#define PMAPPROC_GETPORT 3
/*
* Generic RPC headers
@ -119,8 +115,8 @@ struct rpc_reply {
* Returns non-zero error on failure.
*/
int
krpc_portmap(sa, prog, vers, portp)
struct sockaddr *sa; /* server address */
krpc_portmap(sin, prog, vers, portp)
struct sockaddr_in *sin; /* server address */
u_long prog, vers; /* host order */
u_short *portp; /* network order */
{
@ -156,8 +152,9 @@ krpc_portmap(sa, prog, vers, portp)
sdata->proto = htonl(IPPROTO_UDP);
sdata->port = 0;
error = krpc_call(sa, PMAPPROG, PMAPVERS,
PMAPPROC_GETPORT, &m);
sin->sin_port = htons(PMAPPORT);
error = krpc_call(sin, PMAPPROG, PMAPVERS,
PMAPPROC_GETPORT, &m, NULL);
if (error)
return error;
@ -170,17 +167,19 @@ krpc_portmap(sa, prog, vers, portp)
/*
* Do a remote procedure call (RPC) and wait for its reply.
* If from_p is non-null, then we are doing broadcast, and
* the address from whence the response came is saved there.
*/
int
krpc_call(sa, prog, vers, func, data)
struct sockaddr *sa;
krpc_call(sa, prog, vers, func, data, from_p)
struct sockaddr_in *sa;
u_long prog, vers, func;
struct mbuf **data; /* input/output */
struct mbuf **from_p; /* output */
{
struct socket *so;
struct sockaddr_in *sin;
struct timeval *tv;
struct mbuf *m, *nam, *mhead;
struct mbuf *m, *nam, *mhead, *from;
struct rpc_call *call;
struct rpc_reply *reply;
struct uio auio;
@ -192,11 +191,12 @@ krpc_call(sa, prog, vers, func, data)
* Validate address family.
* Sorry, this is INET specific...
*/
if (sa->sa_family != AF_INET)
if (sa->sin_family != AF_INET)
return (EAFNOSUPPORT);
/* Free at end if not null. */
nam = mhead = NULL;
from = NULL;
/*
* Create socket and set its recieve timeout.
@ -208,13 +208,32 @@ krpc_call(sa, prog, vers, func, data)
if (m == NULL) {
error = ENOBUFS;
goto out;
} else {
struct timeval *tv;
tv = mtod(m, struct timeval *);
m->m_len = sizeof(*tv);
tv->tv_sec = 1;
tv->tv_usec = 0;
if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
goto out;
}
/*
* Enable broadcast if necessary.
*/
if (from_p) {
int *on;
m = m_get(M_WAIT, MT_SOOPTS);
if (m == NULL) {
error = ENOBUFS;
goto out;
}
on = mtod(m, int *);
m->m_len = sizeof(*on);
*on = 1;
if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m)))
goto out;
}
tv = mtod(m, struct timeval *);
m->m_len = sizeof(*tv);
tv->tv_sec = 1;
tv->tv_usec = 0;
if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
goto out;
/*
* Bind the local endpoint to a reserved port,
@ -248,13 +267,7 @@ krpc_call(sa, prog, vers, func, data)
goto out;
}
sin = mtod(nam, struct sockaddr_in *);
bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sa_len));
/*
* Set the port number that the request will use.
*/
if ((error = krpc_portmap(sa, prog, vers, &sin->sin_port)))
goto out;
bcopy((caddr_t)sa, (caddr_t)sin, (nam->m_len = sa->sin_len));
/*
* Prepend RPC message header.
@ -280,7 +293,8 @@ krpc_call(sa, prog, vers, func, data)
*/
call = mtod(mhead, struct rpc_call *);
bzero((caddr_t)call, sizeof(*call));
call->rp_xid = ++xid; /* no need to put in network order */
xid++;
call->rp_xid = htonl(xid);
/* call->rp_direction = 0; */
call->rp_rpcvers = htonl(2);
call->rp_prog = htonl(prog);
@ -322,9 +336,17 @@ krpc_call(sa, prog, vers, func, data)
*/
secs = timo;
while (secs > 0) {
if (from) {
m_freem(from);
from = NULL;
}
if (m) {
m_freem(m);
m = NULL;
}
auio.uio_resid = len = 1<<16;
rcvflg = 0;
error = soreceive(so, NULL, &auio, &m, NULL, &rcvflg);
error = soreceive(so, &from, &auio, &m, NULL, &rcvflg);
if (error == EWOULDBLOCK) {
secs--;
continue;
@ -333,20 +355,35 @@ krpc_call(sa, prog, vers, func, data)
goto out;
len -= auio.uio_resid;
/* Is the reply complete and the right one? */
if (len < MIN_REPLY_HDR) {
m_freem(m);
/* Does the reply contain at least a header? */
if (len < MIN_REPLY_HDR)
continue;
if (m->m_len < MIN_REPLY_HDR)
continue;
reply = mtod(m, struct rpc_reply *);
/* Is it the right reply? */
if (reply->rp_direction != htonl(RPC_REPLY))
continue;
if (reply->rp_xid != htonl(xid))
continue;
/* Was RPC accepted? (authorization OK) */
if (reply->rp_astatus != 0) {
error = ntohl(reply->rp_u.rpu_errno);
printf("rpc denied, error=%d\n", error);
continue;
}
if (m->m_len < MIN_REPLY_HDR) {
m = m_pullup(m, MIN_REPLY_HDR);
if (!m)
continue;
/* Did the call succeed? */
if ((error = ntohl(reply->rp_u.rpu_ok.rp_rstatus)) != 0) {
printf("rpc status=%d\n", error);
continue;
}
reply = mtod(m, struct rpc_reply *);
if ((reply->rp_direction == htonl(RPC_REPLY)) &&
(reply->rp_xid == xid))
goto gotreply; /* break two levels */
goto gotreply; /* break two levels */
} /* while secs */
} /* forever send/receive */
@ -373,22 +410,7 @@ krpc_call(sa, prog, vers, func, data)
error = ENOBUFS;
goto out;
}
}
reply = mtod(m, struct rpc_reply *);
/*
* Check RPC acceptance and status.
*/
if (reply->rp_astatus != 0) {
error = ntohl(reply->rp_u.rpu_errno);
printf("rpc denied, error=%d\n", error);
m_freem(m);
goto out;
}
if ((error = ntohl(reply->rp_u.rpu_ok.rp_rstatus)) != 0) {
printf("rpc status=%d\n", error);
m_freem(m);
goto out;
reply = mtod(m, struct rpc_reply *);
}
/*
@ -403,10 +425,15 @@ krpc_call(sa, prog, vers, func, data)
/* result */
*data = m;
if (from_p) {
*from_p = from;
from = NULL;
}
out:
if (nam) m_freem(nam);
if (mhead) m_freem(mhead);
if (from) m_freem(from);
soclose(so);
return error;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_boot.c,v 1.10 1994/08/11 23:47:51 mycroft Exp $ */
/* $NetBSD: nfs_boot.c,v 1.11 1994/09/26 16:42:33 gwr Exp $ */
/*
* Copyright (c) 1994 Adam Glass, Gordon Ross
@ -48,9 +48,19 @@
#include <nfs/nfsv2.h>
#include <nfs/nfs.h>
#include <nfs/nfsdiskless.h>
#include <nfs/krpc.h>
#include "ether.h"
#if NETHER > 0
#if NETHER == 0
int nfs_boot_init(nd, procp)
struct nfs_diskless *nd;
struct proc *procp;
{
panic("nfs_boot_init: no ether");
}
#else /* NETHER */
/*
* Support for NFS diskless booting, specifically getting information
@ -96,7 +106,7 @@ nfs_boot_init(nd, procp)
struct proc *procp;
{
struct ifreq ireq;
struct in_addr my_ip, srv_ip, gw_ip;
struct in_addr my_ip, gw_ip;
struct sockaddr_in bp_sin;
struct sockaddr_in *sin;
struct ifnet *ifp;
@ -149,10 +159,9 @@ nfs_boot_init(nd, procp)
* Do RARP for the interface address. Also
* save the server address for bootparam RPC.
*/
if ((error = revarpwhoarewe(ifp, &srv_ip, &my_ip)) != 0)
if ((error = revarpwhoami(&my_ip, ifp)) != 0)
panic("revarp failed, error=%d", error);
printf("nfs_boot: client=0x%x, server=0x%x\n",
ntohl(my_ip.s_addr), ntohl(srv_ip.s_addr));
printf("nfs_boot: client_addr=0x%x\n", ntohl(my_ip.s_addr));
/*
* Do enough of ifconfig(8) so that the chosen interface can
@ -173,17 +182,21 @@ nfs_boot_init(nd, procp)
/*
* Get client name and gateway address.
* RPC: bootparam/whoami
* XXX - Using old broadcast addr. for WHOAMI,
* then it is replaced with the BP server addr.
*/
bzero((caddr_t)&bp_sin, sizeof(bp_sin));
bp_sin.sin_len = sizeof(bp_sin);
bp_sin.sin_family = AF_INET;
bp_sin.sin_addr.s_addr = srv_ip.s_addr;
bp_sin.sin_addr.s_addr = ~0; /* XXX */
hostnamelen = MAXHOSTNAMELEN;
/* this returns gateway IP address */
error = bp_whoami(&bp_sin, &my_ip, &gw_ip);
if (error)
panic("nfs_boot: bootparam whoami, error=%d", error);
printf("nfs_boot: server_addr=0x%x\n",
ntohl(bp_sin.sin_addr.s_addr));
printf("nfs_boot: hostname=%s\n", hostname);
#ifdef NFS_BOOT_GATEWAY
@ -315,16 +328,6 @@ struct bp_inaddr {
};
/*
* RPC definitions for bootparamd
* (XXX - move to a header file?)
*/
#define BOOTPARAM_PROG 100026
#define BOOTPARAM_VERS 1
#define BOOTPARAM_WHOAMI 1
#define BOOTPARAM_GETFILE 2
/*
* RPC: bootparam/whoami
* Given client IP address, get:
@ -334,6 +337,12 @@ struct bp_inaddr {
*
* Setting the hostname and domainname here may be somewhat
* controvercial, but it is so easy to do it here. -gwr
*
* Note - bpsin is initialized to the broadcast address,
* and will be replaced with the bootparam server address
* after this call is complete. Have to use PMAP_PROC_CALL
* to make sure we get responses only from a servers that
* know about us (don't want to broadcast a getport call).
*/
static int
bp_whoami(bpsin, my_ip, gw_ip)
@ -341,42 +350,55 @@ bp_whoami(bpsin, my_ip, gw_ip)
struct in_addr *my_ip;
struct in_addr *gw_ip;
{
/* The RPC structures */
struct bp_inaddr *bia;
/* RPC structures for PMAPPROC_CALLIT */
struct whoami_call {
u_long call_prog;
u_long call_vers;
u_long call_proc;
u_long call_arglen;
struct bp_inaddr call_ia;
} *call;
struct rpc_string *str;
struct mbuf *m;
struct bp_inaddr *bia;
struct mbuf *m, *from;
struct sockaddr_in *sin;
int error, msg_len;
int cn_len, dn_len;
u_char *p;
long *lp;
/*
* Get message buffer of sufficient size.
*/
msg_len = sizeof(*bia);
msg_len = sizeof(*call);
m = m_get_len(msg_len);
if (m == NULL)
return ENOBUFS;
/*
* Build request message.
* Build request message for PMAPPROC_CALLIT.
*/
/* client IP address */
bia = mtod(m, struct bp_inaddr *);
bia->atype = htonl(1);
p = (u_char*)my_ip; /* ugh! */
bia->addr[0] = htonl(*p);
p++;
bia->addr[1] = htonl(*p);
p++;
bia->addr[2] = htonl(*p);
p++;
bia->addr[3] = htonl(*p);
p++;
call = mtod(m, struct whoami_call *);
call->call_prog = BOOTPARAM_PROG;
call->call_vers = BOOTPARAM_VERS;
call->call_proc = BOOTPARAM_WHOAMI;
call->call_arglen = sizeof(struct bp_inaddr);
/* RPC: bootparam/whoami */
error = krpc_call((struct sockaddr *)bpsin,
BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_WHOAMI, &m);
/* client IP address */
call->call_ia.atype = htonl(1);
p = (u_char*)my_ip;
lp = call->call_ia.addr;
*lp++ = htonl(*p); p++;
*lp++ = htonl(*p); p++;
*lp++ = htonl(*p); p++;
*lp++ = htonl(*p); p++;
/* RPC: portmap/callit */
bpsin->sin_port = htons(PMAPPORT);
from = NULL;
error = krpc_call(bpsin, PMAPPROG, PMAPVERS,
PMAPPROC_CALLIT, &m, &from);
if (error)
return error;
@ -384,7 +406,21 @@ bp_whoami(bpsin, my_ip, gw_ip)
* Parse result message.
*/
msg_len = m->m_len;
p = mtod(m, char *);
lp = mtod(m, long *);
/* bootparam server port (also grab from address). */
if (msg_len < sizeof(*lp))
goto bad;
msg_len -= sizeof(*lp);
bpsin->sin_port = (short) *lp++;
sin = mtod(from, struct sockaddr_in *);
bpsin->sin_addr.s_addr = sin->sin_addr.s_addr;
/* length of encapsulated results */
if (msg_len < (*lp + sizeof(*lp)))
goto bad;
msg_len = *lp++;
p = (char*)lp;
/* client name */
if (msg_len < sizeof(*str))
@ -434,6 +470,8 @@ bad:
error = EBADRPC;
out:
if (from)
m_freem(from);
m_freem(m);
return(error);
}
@ -490,8 +528,8 @@ bp_getfile(bpsin, key, md_sin, serv_name, pathname)
bcopy(key, str->data, key_len);
/* RPC: bootparam/getfile */
error = krpc_call((struct sockaddr *)bpsin,
BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, &m);
error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS,
BOOTPARAM_GETFILE, &m, NULL);
if (error)
return error;
@ -576,6 +614,11 @@ md_mount(mdsin, path, fhp)
struct mbuf *m;
int error, mlen, slen;
/* Get port number for MOUNTD. */
error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
&mdsin->sin_port);
if (error) return error;
slen = strlen(path);
mlen = RPC_STR_SIZE(slen);
@ -587,8 +630,8 @@ md_mount(mdsin, path, fhp)
bcopy(path, str->data, slen);
/* Do RPC to mountd. */
error = krpc_call((struct sockaddr *)mdsin,
RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT, &m);
error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
RPCMNT_MOUNT, &m, NULL);
if (error)
return error; /* message already freed */
@ -602,8 +645,8 @@ md_mount(mdsin, path, fhp)
bcopy(rdata->fh, fhp, NFS_FHSIZE);
/* Set port number for NFS use. */
error = krpc_portmap((struct sockaddr *)mdsin,
NFS_PROG, NFS_VER2, &mdsin->sin_port);
error = krpc_portmap(mdsin, NFS_PROG, NFS_VER2,
&mdsin->sin_port);
goto out;
bad:
@ -614,13 +657,4 @@ out:
return error;
}
#else /* NETHER */
int nfs_boot_init(nd, procp)
struct nfs_diskless *nd;
struct proc *procp;
{
panic("nfs_boot_init: no ether");
}
#endif /* NETHER */