Do the first BOOTPARAM RPC call to the broadcast address instead of trunk
authorgwr <gwr@NetBSD.org>
Mon, 26 Sep 1994 16:42:29 +0000
branchtrunk
changeset 10064 a2f7b277f053
parent 10063 3e3a090094f5
child 10065 0b881742b9a6
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.
sys/nfs/krpc.h
sys/nfs/krpc_subr.c
sys/nfs/nfs_boot.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/nfs/krpc.h	Mon Sep 26 16:42:29 1994 +0000
@@ -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
+
--- a/sys/nfs/krpc_subr.c	Mon Sep 26 06:54:38 1994 +0000
+++ b/sys/nfs/krpc_subr.c	Mon Sep 26 16:42:29 1994 +0000
@@ -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 @@
  * 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 @@
 	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 @@
 
 /*
  * 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 @@
 	 * 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 @@
 	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;
 	}
-	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;
+	}
 
 	/*
 	 * Bind the local endpoint to a reserved port,
@@ -248,13 +267,7 @@
 		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 @@
 	 */
 	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 @@
 		 */
 		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 @@
 				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 @@
 			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 @@
 
 	/* 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;
 }
--- a/sys/nfs/nfs_boot.c	Mon Sep 26 06:54:38 1994 +0000
+++ b/sys/nfs/nfs_boot.c	Mon Sep 26 16:42:29 1994 +0000
@@ -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 @@
 	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 @@
 	 * 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 @@
 	/*
 	 * 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
@@ -316,16 +329,6 @@
 
 
 /*
- * 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:
  *	client name	(hostname)
@@ -334,6 +337,12 @@
  *
  * 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 @@
 	struct in_addr *my_ip;
 	struct in_addr *gw_ip;
 {
-	/* The RPC structures */
+	/* 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 bp_inaddr *bia;
-	struct rpc_string *str;
-	struct mbuf *m;
+	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.
 	 */
+	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);
+
 	/* 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->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: bootparam/whoami */
-	error = krpc_call((struct sockaddr *)bpsin,
-	    BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_WHOAMI, &m);
+	/* 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 @@
 	 * 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 @@
 	error = EBADRPC;
 
 out:
+	if (from)
+		m_freem(from);
 	m_freem(m);
 	return(error);
 }
@@ -490,8 +528,8 @@
 	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 @@
 	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 @@
 	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 @@
 	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 @@
 	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 */