revised nfs diskless support. uses bootp+rpc to gather parameters trunk
authorglass <glass@NetBSD.org>
Mon, 18 Apr 1994 06:18:05 +0000
branchtrunk
changeset 7083 3c4ddd567db1
parent 7082 a55cba89922c
child 7084 94168984a2ee
revised nfs diskless support. uses bootp+rpc to gather parameters
sys/conf/files
sys/conf/files.newconf
sys/conf/files.oldconf
sys/net/if_ethersubr.c
sys/netinet/if_arp.c
sys/netinet/if_ether.c
sys/nfs/krpc_subr.c
sys/nfs/nfs_boot.c
sys/nfs/nfs_vfsops.c
sys/nfs/rpcv2.h
sys/nfs/swapnfs.c
--- a/sys/conf/files	Mon Apr 18 06:15:08 1994 +0000
+++ b/sys/conf/files	Mon Apr 18 06:18:05 1994 +0000
@@ -1,4 +1,4 @@
-#	$Id: files,v 1.43 1994/03/26 04:13:48 glass Exp $
+#	$Id: files,v 1.44 1994/04/18 06:18:05 glass Exp $
 #
 ddb/db_access.c		optional ddb
 ddb/db_aout.c		optional ddb
@@ -200,7 +200,9 @@
 netns/ns_proto.c	optional ns
 netns/spp_debug.c	optional ns
 netns/spp_usrreq.c	optional ns
+nfs/krpc_subr.c		optional nfsclient requires inet
 nfs/nfs_bio.c		optional nfsclient requires inet
+nfs/nfs_boot.c		optional nfsclient requires inet
 nfs/nfs_node.c		optional nfsclient requires inet
 nfs/nfs_serv.c		optional nfsserver requires inet
 nfs/nfs_socket.c	optional nfsserver or nfsclient requires inet
--- a/sys/conf/files.newconf	Mon Apr 18 06:15:08 1994 +0000
+++ b/sys/conf/files.newconf	Mon Apr 18 06:18:05 1994 +0000
@@ -238,7 +238,9 @@
 file netns/ns_proto.c	 	ns
 file netns/spp_debug.c	 	ns
 file netns/spp_usrreq.c	 	ns
+file nfs/krpc_subr.c		nfsclient
 file nfs/nfs_bio.c		nfsclient
+file nfs/nfs_boot.c		nfsclient
 file nfs/nfs_node.c		nfsclient
 file nfs/nfs_serv.c		nfsserver
 file nfs/nfs_socket.c	 	nfsserver nfsclient
--- a/sys/conf/files.oldconf	Mon Apr 18 06:15:08 1994 +0000
+++ b/sys/conf/files.oldconf	Mon Apr 18 06:18:05 1994 +0000
@@ -1,4 +1,4 @@
-#	$Id: files.oldconf,v 1.43 1994/03/26 04:13:48 glass Exp $
+#	$Id: files.oldconf,v 1.44 1994/04/18 06:18:05 glass Exp $
 #
 ddb/db_access.c		optional ddb
 ddb/db_aout.c		optional ddb
@@ -200,7 +200,9 @@
 netns/ns_proto.c	optional ns
 netns/spp_debug.c	optional ns
 netns/spp_usrreq.c	optional ns
+nfs/krpc_subr.c		optional nfsclient requires inet
 nfs/nfs_bio.c		optional nfsclient requires inet
+nfs/nfs_boot.c		optional nfsclient requires inet
 nfs/nfs_node.c		optional nfsclient requires inet
 nfs/nfs_serv.c		optional nfsserver requires inet
 nfs/nfs_socket.c	optional nfsserver or nfsclient requires inet
--- a/sys/net/if_ethersubr.c	Mon Apr 18 06:15:08 1994 +0000
+++ b/sys/net/if_ethersubr.c	Mon Apr 18 06:18:05 1994 +0000
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)if_ethersubr.c	7.13 (Berkeley) 4/20/91
- *	$Id: if_ethersubr.c,v 1.6 1994/02/02 01:21:36 hpeyerl Exp $
+ *	$Id: if_ethersubr.c,v 1.7 1994/04/18 06:18:10 glass Exp $
  */
 
 #include <sys/param.h>
@@ -315,6 +315,10 @@
 	case ETHERTYPE_ARP:
 		arpinput((struct arpcom *)ifp, m);
 		return;
+
+	case ETHERTYPE_REVARP:
+		revarpinput((struct arpcom *) ifp, m);
+		return;
 #endif
 #ifdef NS
 	case ETHERTYPE_NS:
--- a/sys/netinet/if_arp.c	Mon Apr 18 06:15:08 1994 +0000
+++ b/sys/netinet/if_arp.c	Mon Apr 18 06:18:05 1994 +0000
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)if_ether.c	7.13 (Berkeley) 10/31/90
- *	$Id: if_arp.c,v 1.8 1994/02/02 05:58:50 hpeyerl Exp $
+ *	$Id: if_arp.c,v 1.9 1994/04/18 06:18:16 glass Exp $
  */
 
 /*
@@ -96,6 +96,12 @@
 #define	ARPT_KILLC	20	/* kill completed entry in 20 mins. */
 #define	ARPT_KILLI	3	/* kill incomplete entry in 3 minutes */
 
+/* revarp state*/
+struct in_addr myip; 
+int myip_initialized = 0;
+int revarp_in_progress = 0;
+struct ifnet *myip_ifp = NULL;
+
 extern struct ifnet loif;
 
 /*
@@ -613,3 +619,153 @@
 	splx(s);
 	return (0);
 }
+
+/*
+ * Called from 10 Mb/s Ethernet interrupt handlers
+ * when ether packet type ETHERTYPE_REVARP
+ * is received.  Common length and type checks are done here,
+ * then the protocol-specific routine is called.
+ */
+void revarpinput(ac, m)
+	struct arpcom *ac;
+	struct mbuf *m;
+{
+	struct arphdr *ar;
+	int op, s;
+
+	if (m->m_len < sizeof(struct arphdr))
+		goto out;
+	ar = mtod(m, struct arphdr *);
+	if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
+		goto out;
+	if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln +
+	    2 * ar->ar_pln)	
+		goto out;
+	switch (ntohs(ar->ar_pro)) {
+
+	case ETHERTYPE_IP:
+	case ETHERTYPE_IPTRAILERS:
+		in_revarpinput(ac, m);
+		return;
+
+	default:
+		break;
+	}
+out:
+	m_freem(m);
+}
+
+/*
+ * RARP for Internet protocols on 10 Mb/s Ethernet.
+ * Algorithm is that given in RFC 903.
+ * We are only using for bootstrap purposes to get an ip address for one of
+ * our interfaces.  Thus we support no user-interface.
+ *
+ * Since the contents of the RARP reply are specific to the interface that
+ * sent the request, this code must ensure that they are properly associated.
+ *
+ * Note: also supports ARP via RARP packets, per the RFC.
+ */
+in_revarpinput(ac, m)
+	struct arpcom *ac;
+	struct mbuf *m;
+{
+	struct ether_arp *ar;
+	int op, s;
+
+	ar = mtod(m, struct ether_arp *);
+	op = ntohs(ar->arp_op);
+	switch (op) {
+	case ARPOP_REQUEST:
+	case ARPOP_REPLY:	/* per RFC */
+		if (ac->ac_if.if_flags & IFF_NOARP)
+			goto out;
+		in_arpinput(ac, m);
+		return;
+		break;
+	case REVARP_REPLY:
+		break;
+	case REVARP_REQUEST:	/* handled by rarpd(8) */
+	default:
+		goto out;
+	}
+	if (!revarp_in_progress)
+		goto out;
+	if ((struct ifnet *) ac != myip_ifp) /* !same interface */
+		goto out;
+	if (myip_initialized != 0)
+		goto out;
+	if (bcmp(ar->arp_tha, ac->ac_enaddr, sizeof(ar->arp_tha)))
+		goto out;
+	bcopy((caddr_t) ar->arp_tpa, (caddr_t) &myip, sizeof(myip));
+	myip_initialized = 1;
+	wakeup((caddr_t) &myip);
+ out:
+	m_freem(m);
+}
+
+/*
+ * Send a RARP request for the ip address of the specified interface.
+ * The request should be RFC 903-compliant.
+ */
+void revarp_request(ifp)
+	struct ifnet *ifp;
+{
+	struct sockaddr sa;
+	struct mbuf *m;
+	struct ether_header *eh;
+	struct ether_arp *ea;
+	struct arpcom *ac = (struct arpcom *) ifp;
+
+	if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
+		return;
+	m->m_len = sizeof(*ea);
+	m->m_pkthdr.len = sizeof(*ea);
+	MH_ALIGN(m, sizeof(*ea));
+	ea = mtod(m, struct ether_arp *);
+	eh = (struct ether_header *) sa.sa_data;
+	bzero((caddr_t)ea, sizeof (*ea));
+	bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
+	      sizeof(eh->ether_dhost));
+	eh->ether_type = htons(ETHERTYPE_REVARP);
+	ea->arp_hrd = htons(ARPHRD_ETHER);
+	ea->arp_pro = htons(ETHERTYPE_IP);
+	ea->arp_hln = sizeof(ea->arp_sha);	/* hardware address length */
+	ea->arp_pln = sizeof(ea->arp_spa);	/* protocol address length */
+	ea->arp_op = htons(REVARP_REQUEST);
+	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
+	   sizeof(ea->arp_sha));
+	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_tha,
+	   sizeof(ea->arp_tha));
+	sa.sa_family = AF_UNSPEC;
+	sa.sa_len = sizeof(sa);
+	ifp->if_output(ifp, m, &sa, (struct rtentry *)0);
+}
+
+/*
+ * RARP for the ip address of the specified interface.  Timeout if
+ * no response is received.
+ */
+int revarp_whoami(in, ifp)
+	struct in_addr *in;
+	struct ifnet *ifp;
+{
+	int result, count = 20;
+	
+	if (myip_initialized) 
+		return EIO;
+
+	myip_ifp = ifp;
+	revarp_in_progress = 1;
+	while (count--) {
+		revarp_request(ifp);
+		result = tsleep((caddr_t) &myip, PSOCK, "revarp", hz/2);
+		if (result != EWOULDBLOCK) break;
+	}
+	revarp_in_progress = 0;
+	if (!myip_initialized)
+		return ENETUNREACH;
+	
+	bcopy((caddr_t) &myip, in, sizeof(*in));
+	return 0;
+}
--- a/sys/netinet/if_ether.c	Mon Apr 18 06:15:08 1994 +0000
+++ b/sys/netinet/if_ether.c	Mon Apr 18 06:18:05 1994 +0000
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)if_ether.c	7.13 (Berkeley) 10/31/90
- *	$Id: if_ether.c,v 1.8 1994/02/02 05:58:50 hpeyerl Exp $
+ *	$Id: if_ether.c,v 1.9 1994/04/18 06:18:16 glass Exp $
  */
 
 /*
@@ -96,6 +96,12 @@
 #define	ARPT_KILLC	20	/* kill completed entry in 20 mins. */
 #define	ARPT_KILLI	3	/* kill incomplete entry in 3 minutes */
 
+/* revarp state*/
+struct in_addr myip; 
+int myip_initialized = 0;
+int revarp_in_progress = 0;
+struct ifnet *myip_ifp = NULL;
+
 extern struct ifnet loif;
 
 /*
@@ -613,3 +619,153 @@
 	splx(s);
 	return (0);
 }
+
+/*
+ * Called from 10 Mb/s Ethernet interrupt handlers
+ * when ether packet type ETHERTYPE_REVARP
+ * is received.  Common length and type checks are done here,
+ * then the protocol-specific routine is called.
+ */
+void revarpinput(ac, m)
+	struct arpcom *ac;
+	struct mbuf *m;
+{
+	struct arphdr *ar;
+	int op, s;
+
+	if (m->m_len < sizeof(struct arphdr))
+		goto out;
+	ar = mtod(m, struct arphdr *);
+	if (ntohs(ar->ar_hrd) != ARPHRD_ETHER)
+		goto out;
+	if (m->m_len < sizeof(struct arphdr) + 2 * ar->ar_hln +
+	    2 * ar->ar_pln)	
+		goto out;
+	switch (ntohs(ar->ar_pro)) {
+
+	case ETHERTYPE_IP:
+	case ETHERTYPE_IPTRAILERS:
+		in_revarpinput(ac, m);
+		return;
+
+	default:
+		break;
+	}
+out:
+	m_freem(m);
+}
+
+/*
+ * RARP for Internet protocols on 10 Mb/s Ethernet.
+ * Algorithm is that given in RFC 903.
+ * We are only using for bootstrap purposes to get an ip address for one of
+ * our interfaces.  Thus we support no user-interface.
+ *
+ * Since the contents of the RARP reply are specific to the interface that
+ * sent the request, this code must ensure that they are properly associated.
+ *
+ * Note: also supports ARP via RARP packets, per the RFC.
+ */
+in_revarpinput(ac, m)
+	struct arpcom *ac;
+	struct mbuf *m;
+{
+	struct ether_arp *ar;
+	int op, s;
+
+	ar = mtod(m, struct ether_arp *);
+	op = ntohs(ar->arp_op);
+	switch (op) {
+	case ARPOP_REQUEST:
+	case ARPOP_REPLY:	/* per RFC */
+		if (ac->ac_if.if_flags & IFF_NOARP)
+			goto out;
+		in_arpinput(ac, m);
+		return;
+		break;
+	case REVARP_REPLY:
+		break;
+	case REVARP_REQUEST:	/* handled by rarpd(8) */
+	default:
+		goto out;
+	}
+	if (!revarp_in_progress)
+		goto out;
+	if ((struct ifnet *) ac != myip_ifp) /* !same interface */
+		goto out;
+	if (myip_initialized != 0)
+		goto out;
+	if (bcmp(ar->arp_tha, ac->ac_enaddr, sizeof(ar->arp_tha)))
+		goto out;
+	bcopy((caddr_t) ar->arp_tpa, (caddr_t) &myip, sizeof(myip));
+	myip_initialized = 1;
+	wakeup((caddr_t) &myip);
+ out:
+	m_freem(m);
+}
+
+/*
+ * Send a RARP request for the ip address of the specified interface.
+ * The request should be RFC 903-compliant.
+ */
+void revarp_request(ifp)
+	struct ifnet *ifp;
+{
+	struct sockaddr sa;
+	struct mbuf *m;
+	struct ether_header *eh;
+	struct ether_arp *ea;
+	struct arpcom *ac = (struct arpcom *) ifp;
+
+	if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
+		return;
+	m->m_len = sizeof(*ea);
+	m->m_pkthdr.len = sizeof(*ea);
+	MH_ALIGN(m, sizeof(*ea));
+	ea = mtod(m, struct ether_arp *);
+	eh = (struct ether_header *) sa.sa_data;
+	bzero((caddr_t)ea, sizeof (*ea));
+	bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
+	      sizeof(eh->ether_dhost));
+	eh->ether_type = htons(ETHERTYPE_REVARP);
+	ea->arp_hrd = htons(ARPHRD_ETHER);
+	ea->arp_pro = htons(ETHERTYPE_IP);
+	ea->arp_hln = sizeof(ea->arp_sha);	/* hardware address length */
+	ea->arp_pln = sizeof(ea->arp_spa);	/* protocol address length */
+	ea->arp_op = htons(REVARP_REQUEST);
+	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
+	   sizeof(ea->arp_sha));
+	bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_tha,
+	   sizeof(ea->arp_tha));
+	sa.sa_family = AF_UNSPEC;
+	sa.sa_len = sizeof(sa);
+	ifp->if_output(ifp, m, &sa, (struct rtentry *)0);
+}
+
+/*
+ * RARP for the ip address of the specified interface.  Timeout if
+ * no response is received.
+ */
+int revarp_whoami(in, ifp)
+	struct in_addr *in;
+	struct ifnet *ifp;
+{
+	int result, count = 20;
+	
+	if (myip_initialized) 
+		return EIO;
+
+	myip_ifp = ifp;
+	revarp_in_progress = 1;
+	while (count--) {
+		revarp_request(ifp);
+		result = tsleep((caddr_t) &myip, PSOCK, "revarp", hz/2);
+		if (result != EWOULDBLOCK) break;
+	}
+	revarp_in_progress = 0;
+	if (!myip_initialized)
+		return ENETUNREACH;
+	
+	bcopy((caddr_t) &myip, in, sizeof(*in));
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/nfs/krpc_subr.c	Mon Apr 18 06:18:05 1994 +0000
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 1994 Gordon Ross, Adam Glass 
+ * Copyright (c) 1992 Regents of the University of California.
+ * All rights reserved.
+ *
+ * This software was developed by the Computer Systems Engineering group
+ * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
+ * contributed to Berkeley.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by the University of
+ *	California, Lawrence Berkeley Laboratory and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * partially based on:
+ *      libnetboot/rpc.c
+ *               @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp  (LBL)
+ *   $Id: krpc_subr.c,v 1.1 1994/04/18 06:18:19 glass Exp $
+ */
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/reboot.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <nfs/rpcv2.h>
+
+/*
+ * Kernel support for Sun RPC
+ *
+ * Used currently for bootstrapping in nfs diskless configurations.
+ * 
+ * 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
+ */
+
+struct auth_info {
+	int	rp_atype;		/* auth type */
+	u_long	rp_alen;		/* auth length */
+};
+
+struct rpc_call {
+	u_long	rp_xid;			/* request transaction id */
+	int 	rp_direction;	        /* call direction (0) */
+	u_long	rp_rpcvers;		/* rpc version (2) */
+	u_long	rp_prog;		/* program */
+	u_long	rp_vers;		/* version */
+	u_long	rp_proc;		/* procedure */
+	struct	auth_info rp_auth;
+	struct	auth_info rp_verf;
+};
+
+struct rpc_reply {
+	u_long	rp_xid;			/* request transaction id */
+	int	rp_direction;		/* call direction (1) */
+	int	rp_astatus;		/* accept status (0: accepted) */
+	union {
+		u_long	rpu_errno;
+		struct {
+			struct auth_info rp_auth;
+			u_long	rp_rstatus;		/* reply status */
+		} rpu_ok;
+	} rp_u;
+};
+
+#define MIN_REPLY_HDR 16	/* xid, dir, astat, errno */
+
+/*
+ * Call portmap to lookup a port number for a particular rpc program
+ * Returns the port number in host order, or  ZERO if it couldn't.
+ */
+int
+krpc_portmap(sa,  prog, vers, portp)
+	struct sockaddr *sa;		/* server address */
+	u_long prog, vers;	/* host order */
+	u_short *portp;		/* network order */
+{
+	struct sdata {
+		u_long	prog;		/* call program */
+		u_long	vers;		/* call version */
+		u_long	proto;		/* call protocol */
+		u_long	port;		/* call port (unused) */
+	} *sdata;
+	struct rdata {
+		u_short pad;
+		u_short port;
+	} *rdata;
+	struct mbuf *m;
+	int error;
+
+	/* The portmapper port is fixed. */
+	if (prog == PMAPPROG) {
+		*portp = htons(PMAPPORT);
+		return 0;
+	}
+
+	m = m_get(M_WAIT, MT_DATA);
+	if (m == NULL)
+		return ENOBUFS;
+	m->m_len = sizeof(*sdata);
+	sdata = mtod(m, struct sdata *);
+
+	/* Do the RPC to get it. */
+	sdata->prog = htonl(prog);
+	sdata->vers = htonl(vers);
+	sdata->proto = htonl(IPPROTO_UDP);
+	sdata->port = 0;
+
+	error = krpc_call(sa, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
+			  &m, sizeof(*rdata));
+	if (error) 
+		return error;
+
+	rdata = mtod(m, struct rdata *);
+	*portp = rdata->port;
+
+	m_freem(m);
+	return 0;
+}
+
+/*
+ * Do a remote procedure call (RPC) and wait for its reply.
+ */
+int
+krpc_call(sa, prog, vers, func, data, want)
+	struct sockaddr *sa;
+	u_long prog, vers, func;
+	struct mbuf **data;	/* input/output */
+	int want;		/* required response data length */
+{
+	struct socket *so;
+	struct sockaddr_in *sin;
+	struct timeval *tv;
+	struct mbuf *m, *nam, *mhead;
+	struct rpc_call *call;
+	struct rpc_reply *reply;
+	struct uio auio;
+	int error, rcvflg, timo, secs, len;
+	static u_long xid = ~0xFF;
+
+	/*
+	 * Validate address family.
+	 * Sorry, this is INET specific...
+	 */
+	if (sa->sa_family != AF_INET)
+		return (EAFNOSUPPORT);
+
+	/* Free at end if not null. */
+	nam = mhead = NULL;
+
+	/*
+	 * Create socket and set its recieve timeout.
+	 */
+	if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)))
+		goto out;
+
+	m = m_get(M_WAIT, MT_SOOPTS);
+	if (m == NULL) {
+		error = ENOBUFS;
+		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;
+
+	/*
+	 * Setup socket address for the server.
+	 */
+	nam = m_get(M_WAIT, MT_SONAME);
+	if (nam == NULL) {
+		error = ENOBUFS;
+		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;
+
+	/*
+	 * Build the RPC message header.
+	 */
+	mhead = m_gethdr(M_WAIT, MT_DATA);
+	if (mhead == NULL) {
+		error = ENOBUFS;
+		goto out;
+	}
+	mhead->m_len = sizeof(*call);
+	call = mtod(mhead, struct rpc_call *);
+	bzero((caddr_t)call, sizeof(*call));
+	call->rp_xid = ++xid;	/* no need to put in network order */
+	/* call->rp_direction = 0; */
+	call->rp_rpcvers = htonl(2);
+	call->rp_prog = htonl(prog);
+	call->rp_vers = htonl(vers);
+	call->rp_proc = htonl(func);
+	/* call->rp_auth = 0; */
+	/* call->rp_verf = 0; */
+
+	/*
+	 * Prepend RPC header and setup packet header.
+	 */
+	for (len = 0, m = *data; m ; m = m->m_next)
+		len += m->m_len;
+	mhead->m_next = *data;
+	mhead->m_pkthdr.len = mhead->m_len + len;
+	mhead->m_pkthdr.rcvif = NULL;
+	*data = NULL;
+
+	/*
+	 * Send it, repeatedly, until a reply is received, but
+	 * delay each send by an increasing amount. (10 sec. max)
+	 * When the send delay hits 10 sec. start complaining.
+	 */
+	timo = 0;
+	for (;;) {
+		/* Send RPC request (or re-send). */
+		m = m_copym(mhead, 0, M_COPYALL, M_WAIT);
+		error = sosend(so, nam, NULL, m, NULL, 0);
+		if (error)
+			goto out;
+		m = NULL;
+
+		/* Determine new timeout (1 to 10) */
+		if (timo < 10)
+			timo++;
+		else
+			printf("RPC timeout for server 0x%X\n",
+			       ntohl(sin->sin_addr.s_addr));
+
+		/*
+		 * Wait for up to timo seconds for a reply.
+		 * The socket receive timeout was set to 1 second.
+		 */
+		secs = timo;
+		while (secs > 0) {
+			auio.uio_resid = len = 1<<16;
+			rcvflg = 0;
+			error = soreceive(so, NULL, &auio, &m, NULL, &rcvflg);
+			if (error == EWOULDBLOCK) {
+				secs--;
+				continue;
+			}
+			if (error)
+				goto out;
+			len -= auio.uio_resid;
+
+			/* Is the reply complete and the right one? */
+			if (len < MIN_REPLY_HDR) {
+				m_freem(m);
+				continue;
+			}
+			if (m->m_len < MIN_REPLY_HDR) {
+				m = m_pullup(m, MIN_REPLY_HDR);
+				if (!m)
+					continue;
+			}
+			reply = mtod(m, struct rpc_reply *);
+			if ((reply->rp_direction == htonl(RPC_REPLY)) &&
+				(reply->rp_xid == xid))
+				goto gotreply;	/* break two levels */
+		} /* while secs */
+	} /* forever send/receive */
+ gotreply:
+
+	/*
+	 * Got the reply.  Check and strip header.
+	 */
+	if (reply->rp_astatus != 0) {
+		error = reply->rp_u.rpu_errno;
+		m_freem(m);
+		goto out;
+	}
+	len = sizeof(*reply);
+	if (reply->rp_u.rpu_ok.rp_auth.rp_atype != 0) {
+		len += ntohl(reply->rp_u.rpu_ok.rp_auth.rp_alen);
+		len = (len + 3) & ~3; /* XXX? */
+	}
+	m_adj(m, len);
+	if (m == NULL) {
+		error = ENOBUFS;
+		goto out;
+	}
+	if (m->m_len < want) {
+		m = m_pullup(m, want);
+		if (m == NULL) {
+			error = ENOBUFS;
+			goto out;
+		}
+	}
+	/* result */
+	*data = m;
+
+ out:
+	if (nam) m_freem(nam);
+	if (mhead) m_freem(mhead);
+	soclose(so);
+	return error;
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/nfs/nfs_boot.c	Mon Apr 18 06:18:05 1994 +0000
@@ -0,0 +1,401 @@
+/*
+ * Copyright (c) 1994 Adam Glass, Gordon Ross
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by Adam Glass.
+ * 4. The name of the Author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL Adam Glass BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Header: /cvsroot/src/sys/nfs/nfs_boot.c,v 1.1 1994/04/18 06:18:20 glass Exp $
+ */
+
+#include <sys/systm.h>
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/mbuf.h>
+#include <sys/socket.h>
+#include <sys/systm.h>
+#include <sys/reboot.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include <nfs/rpcv2.h>
+#include <nfs/nfsv2.h>
+#include <nfs/nfs.h>
+#include <nfs/nfsdiskless.h>
+
+/*
+ * Support for NFS diskless booting, specifically getting information
+ * about where to boot from, what pathnames, etc.
+ *
+ * We currently support the RPC bootparam protocol.
+ *
+ * We'd like to support BOOTP, but someone needs to write small kernel-ized
+ * BOOTP client
+ *
+ */
+
+/* from rfc951 to avoid bringing in cmu header file */
+
+#define UDP_BOOTPSERVER 67
+#define UDP_BOOTPCLIENT 68
+
+#define BOOTP_REQUEST 1
+#define BOOTP_REPLY   2
+
+/* rfc1048 tag bytes, (from rfc1497), only the semi-useful bits */
+#define TAG_PAD                0	/* [1] no data */
+#define TAG_SUBNET_MASK        1        /* [4] subnet mask bytes */
+#define TAG_GATEWAY_ADDR       3        /* [addr] gateway address */
+#define TAG_DNS_ADDR           6        /* [addr] dns name server */
+#define TAG_HOSTNAME          12        /* [n] hostname */
+#define TAG_BOOT_SIZE         13        /* [2] boot file size?*/
+#define TAG_DOMAIN_NAME       15        /* [n] domain name */
+#define TAG_SWAP_ADDR         16        /* [addr] swap server */
+#define TAG_ROOT_PATH         17        /* [n] root path */
+#define TAG_END              255
+
+#define BOOTP_ROOT 1
+#define BOOTP_SWAP 2
+#define BOOTP_COMPLETED (BOOTP_ROOT|BOOTP_SWAP)
+
+struct bootp_msg {
+	u_char bpm_op;		/* packet op code / message type */
+	u_char bpm_htype;	/* hardware address type */
+	u_char bpm_hlen;	/* hardware address length */
+	u_char bpm_hops;	/* bootp hops XXX ugly*/
+	u_long bpm_xid;		/* transaction ID */
+	u_short bpm_secs;	/* seconds elapsed since boot */
+	u_short bpm_unused;	
+	struct in_addr bpm_ciaddr; /* client IP address */
+	struct in_addr bpm_yiaddr; /* 'your' (client) IP address */
+	struct in_addr bpm_siaddr; /* server IP address */
+	struct in_addr bpm_giaddr; /* gateway IP address */
+	u_char bpm_chaddr[16];	/* client hardware address */
+	u_char bpm_sname[64];	/* optional server host name */
+	u_char bpm_file[128];	/* boot file name */
+	u_char bpm_vendor[64];	/* vendor-specific data */
+};
+
+static u_char vend_rfc1048[4] = {
+	99, 130, 83, 99,
+};
+
+/*
+ * Get a file handle given a path name.
+ */
+static int
+nfs_boot_getfh(sa, path, fhp)
+	struct sockaddr *sa;		/* server address */
+	char *path;
+	u_char *fhp;
+{
+	/* The RPC structures */
+	struct sdata {
+		u_long  len;
+		u_char  path[4];	/* longer, of course */
+	} *sdata;
+	struct rdata {
+		u_long	errno;
+		u_char	fh[NFS_FHSIZE];
+	} *rdata;
+	struct sockaddr_in *sin;
+	struct mbuf *m;
+	int error, mlen, slen;
+
+	/*
+	 * Validate address family.
+	 * Sorry, this is INET specific...
+	 */
+	if (sa->sa_family != AF_INET)
+		return EAFNOSUPPORT;
+
+	slen = strlen(path);
+	if (slen > (MLEN-4))
+		slen = (MLEN-4);
+	mlen = 4 + ((slen + 3) & ~3); /* XXX ??? */
+
+	m = m_get(M_WAIT, MT_DATA);
+	if (m == NULL)
+		return ENOBUFS;
+	m->m_len = mlen;
+	sdata = mtod(m, struct sdata *);
+	sdata->len = htonl(slen);
+	bcopy(path, sdata->path, slen);
+
+	/* Do RPC to mountd. */
+	error = krpc_call(sa, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
+			  &m, sizeof(*rdata));
+	if (error) 
+		return error;
+
+	rdata = mtod(m, struct rdata *);
+	error = ntohl(rdata->errno);
+	if (!error)
+		bcopy(rdata->fh, fhp, NFS_FHSIZE);
+	m_freem(m);
+	return error;
+}
+
+/*
+ * Receive a bootp reply
+ */
+static int bootp_receive(so, msg)
+	struct socket *so;
+	struct bootp_msg *msg;
+{
+	int error, rcvflag = 0;
+	struct mbuf *m;
+	struct uio auio;
+
+	auio.uio_resid = (1<<16);
+
+	error = soreceive(so, NULL, &auio, &m, NULL, &rcvflag);
+	if (error)
+		return error;
+	if (m->m_len < sizeof(*msg)) {
+		m = m_pullup(m, sizeof(*msg));
+		if (m == NULL)
+			return ENOBUFS;
+	}
+	if (((1<<16) - auio.uio_resid) != sizeof(*msg))
+		return EMSGSIZE;
+	m_copydata(m, 0, sizeof(*msg), (caddr_t) msg);
+	return 0;
+}
+
+/*
+ * Send a bootp request
+ */
+static int bootp_send(so, nam, start, msg)
+	struct socket *so;
+	struct mbuf *nam;
+	time_t start;
+	struct bootp_msg *msg;
+{
+	int error;
+	struct mbuf *m;
+	struct bootp_msg *bpm;
+
+	MGETHDR(m, M_WAIT, MT_DATA);
+	m->m_len = MHLEN;
+	if (m->m_len < sizeof(*msg)) {
+		MCLGET(m, M_WAIT);
+		m->m_len = min(sizeof(*msg), MCLBYTES);
+	}
+	m->m_pkthdr.len = sizeof(*msg);
+	m->m_pkthdr.rcvif = NULL;
+	bpm = mtod(m, struct bootp_msg *);
+	bcopy((caddr_t) msg, (caddr_t) bpm, sizeof(*bpm));
+	bpm->bpm_secs = time.tv_sec - start;
+
+	error = sosend(so, nam, NULL, m, NULL, 0);
+	if (error)
+		return error;
+}
+
+/*
+ * Fill in as much of the nfs_diskless struct using the results
+ * of bootp requests.
+ */
+int nfs_boot_bootp(diskless, rpath, spath)
+	struct nfs_diskless *diskless;
+	char *rpath, *spath;
+{
+	int error, bootp_timeout = 30, *opt_val, have, need;
+	time_t start;
+	struct socket *so;
+	struct sockaddr *sa;
+	struct sockaddr_in *sin;
+	struct mbuf *m, *nam;
+	struct timeval *tv;
+	struct bootp_msg outgoing, incoming;
+
+	sa = &diskless->myif.ifra_broadaddr;
+	if (sa->sa_family != AF_INET)
+		return EAFNOSUPPORT;
+
+	/*
+	 * Create socket and set its recieve timeout.
+	 */
+	if (error = socreate(AF_INET, &so, SOCK_DGRAM, 0))
+		return error;
+	nam = m_get(M_WAIT, MT_SONAME);
+	sin = mtod(nam, struct sockaddr_in *);
+	bzero((caddr_t) sin, sizeof(*sin));
+	sin->sin_len = sizeof(struct sockaddr_in);
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = htonl(INADDR_ANY);
+	sin->sin_port = htons(UDP_BOOTPCLIENT);
+	nam->m_len = sizeof(struct sockaddr_in);
+	if (error = sobind(so, nam))
+		goto out;
+	m = m_get(M_WAIT, MT_SOOPTS);
+	tv = mtod(m, struct timeval *);
+	m->m_len = sizeof(*tv);
+	tv->tv_sec = 5;
+	tv->tv_usec = 0;
+	if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
+		goto out;
+	m = m_get(M_WAIT, MT_SOOPTS);
+	opt_val = mtod(m, int *);
+	m->m_len = sizeof(*opt_val);
+	*opt_val = 1;
+	if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m))) 
+		goto out;
+
+	/*
+	 * Setup socket address for the server.
+	 */
+	nam = m_get(M_WAIT, MT_SONAME);
+	sin = mtod(nam, struct sockaddr_in *);
+	bcopy((caddr_t)sa, (caddr_t)sin, sizeof(struct sockaddr));
+	sin->sin_port = htons(UDP_BOOTPSERVER);
+	nam->m_len = sizeof(struct sockaddr);
+	
+	bzero((caddr_t) &outgoing, sizeof(outgoing));
+	outgoing.bpm_op = BOOTP_REQUEST;
+	outgoing.bpm_htype = 1;
+	outgoing.bpm_hlen = 6;
+	outgoing.bpm_hops = 0;
+	sin = (struct sockaddr_in *) &diskless->myif.ifra_addr;
+	bcopy((caddr_t) &sin->sin_addr, (caddr_t) &outgoing.bpm_ciaddr, 4);
+	bcopy((caddr_t) &sin->sin_addr, (caddr_t) &outgoing.bpm_yiaddr, 4);
+	bcopy((caddr_t) vend_rfc1048, (caddr_t) outgoing.bpm_vendor, 4);
+	outgoing.bpm_xid = time.tv_usec;
+	outgoing.bpm_vendor[4] = TAG_END;
+	start = time.tv_sec;
+
+	have = 0;
+	while (bootp_timeout-- && (have != BOOTP_COMPLETED)) {
+		if ((have & BOOTP_ROOT) == 0)
+			strcpy(outgoing.bpm_file, "root");
+		else if ((have & BOOTP_SWAP) == 0)
+			strcpy(outgoing.bpm_file, "swap");
+		if (error = bootp_send(so, nam, start, &outgoing)) {
+			goto out;
+		}
+		error = bootp_receive(so, &incoming);
+		if (error == EWOULDBLOCK) 
+			continue;
+		if (error)
+			goto out;
+
+		if (outgoing.bpm_xid != incoming.bpm_xid)
+			continue;
+		if ((have & BOOTP_ROOT) == 0) {
+			sin = (struct sockaddr_in *) &diskless->root_saddr;
+			sin->sin_family = AF_INET;
+			sin->sin_len = sizeof(*sin);
+			bcopy((caddr_t) &incoming.bpm_siaddr,
+			      (caddr_t) &sin->sin_addr, sizeof(sin->sin_addr));
+			strcpy(diskless->root_hostnam, incoming.bpm_sname);
+			strcpy(rpath, incoming.bpm_file);
+			have |= BOOTP_ROOT;
+			outgoing.bpm_xid++;
+		}
+		else if ((have & BOOTP_SWAP) == 0) {
+			sin = (struct sockaddr_in *) &diskless->swap_saddr;
+			sin->sin_family = AF_INET;
+			sin->sin_len = sizeof(*sin);
+			bcopy((caddr_t) &incoming.bpm_siaddr,
+			      (caddr_t) &sin->sin_addr, sizeof(sin->sin_addr));
+			strcpy(diskless->swap_hostnam, incoming.bpm_sname);
+			strcpy(spath, incoming.bpm_file);
+			have |= BOOTP_SWAP;
+		}
+	}
+		
+	if (have != BOOTP_COMPLETED)
+		error = ETIMEDOUT;
+ out:
+	if (nam)
+		m_freem(nam);
+	soclose(so);
+
+	return error;
+}
+
+/*
+ * Called with a nfs_diskless struct in which a interface ip addr,
+ * broadcast addr, and netmask have been specified.,
+ *
+ * The responsibility of this routine is to fill out the rest of the
+ * struct using whatever mechanism.
+ *
+ */
+int nfs_boot(diskless)
+	struct nfs_diskless *diskless;
+{
+	int error;
+	u_short port;
+	struct sockaddr_in *sin;
+	char root_path[MAXPATHLEN], swap_path[MAXPATHLEN];
+
+	error = nfs_boot_bootp(diskless, root_path, swap_path);
+	if (error)
+		return error;
+
+	sin = (struct sockaddr_in *) &diskless->root_saddr;
+	error = nfs_boot_getfh(&diskless->root_saddr, root_path,
+			       diskless->root_fh);
+	if (error)
+		return error;
+	error = krpc_portmap(&diskless->root_saddr,
+			     NFS_PROG, NFS_VER2, &sin->sin_port);
+	if (error)
+		return error;
+
+	sin = (struct sockaddr_in *) &diskless->swap_saddr;
+	error = nfs_boot_getfh(&diskless->swap_saddr, swap_path,
+			       diskless->swap_fh);
+	if (error)
+		return error;
+	error = krpc_portmap(&diskless->swap_saddr,
+			     NFS_PROG, NFS_VER2, &sin->sin_port);
+	if (error)
+		return error;
+
+	printf("root on %x:%s\n", diskless->root_hostnam, root_path);
+	printf("swap on %x:%s\n", diskless->swap_hostnam, swap_path);
+	diskless->root_args.addr = &diskless->root_saddr;
+	diskless->swap_args.addr = &diskless->swap_saddr;
+	diskless->root_args.sotype = diskless->swap_args.sotype = SOCK_DGRAM;
+	diskless->root_args.proto = diskless->swap_args.proto = 0;
+	diskless->root_args.flags = diskless->swap_args.flags = 0;
+	diskless->root_args.wsize = diskless->swap_args.wsize = NFS_WSIZE;
+	diskless->root_args.rsize = diskless->swap_args.rsize = NFS_RSIZE;
+	diskless->root_args.timeo = diskless->swap_args.timeo = NFS_TIMEO;
+	diskless->root_args.retrans = diskless->swap_args.retrans =
+		NFS_RETRANS;
+	diskless->root_args.hostname = diskless->root_hostnam;
+	diskless->swap_args.hostname = diskless->swap_hostnam;
+	return 0;
+}
--- a/sys/nfs/nfs_vfsops.c	Mon Apr 18 06:15:08 1994 +0000
+++ b/sys/nfs/nfs_vfsops.c	Mon Apr 18 06:18:05 1994 +0000
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)nfs_vfsops.c	7.31 (Berkeley) 5/6/91
- *	$Id: nfs_vfsops.c,v 1.14 1994/04/14 04:06:26 cgd Exp $
+ *	$Id: nfs_vfsops.c,v 1.15 1994/04/18 06:18:22 glass Exp $
  */
 
 #include <sys/param.h>
@@ -83,7 +83,6 @@
 static u_char nfs_mntid;
 extern u_long nfs_procids[NFS_NPROCS];
 extern u_long nfs_prog, nfs_vers;
-struct nfs_diskless nfs_diskless;
 void nfs_disconnect();
 
 #define TRUE	1
@@ -146,17 +145,17 @@
 }
 
 /*
- * Mount a remote root fs via. nfs. This depends on the info in the
- * nfs_diskless structure that has been filled in properly by some primary
- * bootstrap.
- * It goes something like this:
- * - do enough of "ifconfig" by calling ifioctl() so that the system
- *   can talk to the server
- * - If nfs_diskless.mygateway is filled in, use that address as
- *   a default gateway.
- *   (This is done the 4.3 way with rtioctl() and should be changed)
- * - hand craft the swap nfs vnode hanging off a fake mount point
- * - build the rootfs mount point and call mountnfs() to do the rest.
+ * Mount a remote root fs via. nfs.
+ *
+ * Configure up an interface
+ * Initialize a nfs_diskless struct with:
+ *                 ip addr
+ *                 broadcast addr
+ *                 netmask
+ * as acquired and implied by RARP.
+ *
+ * Then call nfs_boot() to fill in the rest of the structure with enough
+ * information to mount root and swap.
  */
 nfs_mountroot()
 {
@@ -164,23 +163,68 @@
 	register struct mbuf *m;
 	struct socket *so;
 	struct vnode *vp;
-	int error;
+	struct ifnet *ifp;
+	struct sockaddr_in *sin;
+	struct in_addr myip;
+	struct ifreq ireq;
+	struct nfs_diskless diskless;
+	int error, len;
 
 	/*
-	 * Do enough of ifconfig(8) so that critical net interface can
-	 * talk to the server.
+	 * Find an interface, rarp for its ip address, stuff it, the
+	 * implied broadcast addr, and netmask into a nfs_diskless struct.
 	 */
-	if (socreate(nfs_diskless.myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
+
+	for (ifp = ifnet; ifp; ifp = ifp->if_next)
+		if ((ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
+			break;
+	if (ifp == NULL)
+		return ENETUNREACH;
+	strcpy(ireq.ifr_name, ifp->if_name);
+	len = strlen(ireq.ifr_name);
+	ireq.ifr_name[len] = '0' + ifp->if_unit; /* XXX */
+	ireq.ifr_name[len+1] = '\0';
+	ireq.ifr_flags = IFF_UP;
+	if (error = ifioctl(NULL, SIOCSIFFLAGS, &ireq, curproc))
+		panic("nfs_mountroot, bringing interface %s up",
+		      ireq.ifr_name);
+	bzero((caddr_t) &diskless, sizeof(diskless));
+	strcpy(diskless.myif.ifra_name, ireq.ifr_name);
+	if (revarp_whoami(&myip, ifp))
+		panic("revarp failed");
+	sin = (struct sockaddr_in *) &ireq.ifr_addr;
+	bzero((caddr_t) sin, sizeof(struct sockaddr_in));
+	sin->sin_len = sizeof(struct sockaddr_in);
+	sin->sin_family = AF_INET;
+	sin->sin_addr = myip;
+
+	/*
+	 * Do enough of ifconfig(8) so that the chosen interface can
+	 * talk to the server(s).
+	 */
+	if (socreate(AF_INET, &so, SOCK_DGRAM, 0))
 		panic("nfs ifconf");
-	if (ifioctl(so, SIOCAIFADDR, &nfs_diskless.myif))
-		panic("nfs ifconf2");
+	if (ifioctl(so, SIOCSIFADDR, &ireq, curproc))
+		panic("nfs_mountroot: setting interface address\n");
+	bcopy((caddr_t) sin, (caddr_t) &diskless.myif.ifra_addr,
+	      sizeof(struct sockaddr));
+	if (ifioctl(so, SIOCGIFBRDADDR, &ireq, curproc))
+		panic("nfs baddr");
+	bcopy((caddr_t) &ireq.ifr_broadaddr,
+	      (caddr_t) &diskless.myif.ifra_broadaddr,
+	      sizeof (ireq.ifr_broadaddr));
+	if (ifioctl(so, SIOCGIFNETMASK, &ireq, curproc))
+		panic("nfs get netmask");
 	soclose(so);
 
+	if (error = nfs_boot(&diskless))
+		return error;
+
 	/*
 	 * If the gateway field is filled in, set it as the default route.
 	 */
 #ifdef COMPAT_43
-	if (nfs_diskless.mygateway.sa_family == AF_INET) {
+	if (diskless.mygateway.sa_family == AF_INET) {
 		struct ortentry rt;
 		struct sockaddr_in *sin;
 
@@ -188,7 +232,7 @@
 		sin->sin_len = sizeof (struct sockaddr_in);
 		sin->sin_family = AF_INET;
 		sin->sin_addr.s_addr = 0;	/* default */
-		bcopy((caddr_t)&nfs_diskless.mygateway, (caddr_t)&rt.rt_gateway,
+		bcopy((caddr_t)&diskless.mygateway, (caddr_t)&rt.rt_gateway,
 			sizeof (struct sockaddr_in));
 		rt.rt_flags = (RTF_UP | RTF_GATEWAY);
 		if (rtioctl(SIOCADDRT, (caddr_t)&rt, curproc))
@@ -217,15 +261,15 @@
 		 * Since the swap file is not the root dir of a file system,
 		 * hack it to a regular file.
 		 */
-		nfs_diskless.swap_args.fh = (nfsv2fh_t *)nfs_diskless.swap_fh;
+		diskless.swap_args.fh = (nfsv2fh_t *)diskless.swap_fh;
 		MGET(m, MT_SONAME, M_DONTWAIT);
 		if (m == NULL)
 			panic("nfs root mbuf");
-		bcopy((caddr_t)&nfs_diskless.swap_saddr, mtod(m, caddr_t),
-			nfs_diskless.swap_saddr.sa_len);
-		m->m_len = nfs_diskless.swap_saddr.sa_len;
-		if (mountnfs(&nfs_diskless.swap_args, mp, m, "/swap",
-			nfs_diskless.swap_hostnam, &vp))
+		bcopy((caddr_t)&diskless.swap_saddr, mtod(m, caddr_t),
+			diskless.swap_saddr.sa_len);
+		m->m_len = diskless.swap_saddr.sa_len;
+		if (mountnfs(&diskless.swap_args, mp, m, "/swap",
+			diskless.swap_hostnam, &vp))
 			panic("nfs swap");
 		vp->v_type = VREG;
 		vp->v_flag = 0;
@@ -257,15 +301,15 @@
 	/*
 	 * Set up the root fs args and call mountnfs() to do the rest.
 	 */
-	nfs_diskless.root_args.fh = (nfsv2fh_t *)nfs_diskless.root_fh;
+	diskless.root_args.fh = (nfsv2fh_t *)diskless.root_fh;
 	MGET(m, MT_SONAME, M_DONTWAIT);
 	if (m == NULL)
 		panic("nfs root mbuf2");
-	bcopy((caddr_t)&nfs_diskless.root_saddr, mtod(m, caddr_t),
-		nfs_diskless.root_saddr.sa_len);
-	m->m_len = nfs_diskless.root_saddr.sa_len;
-	if (mountnfs(&nfs_diskless.root_args, mp, m, "/",
-		nfs_diskless.root_hostnam, &vp))
+	bcopy((caddr_t)&diskless.root_saddr, mtod(m, caddr_t),
+		diskless.root_saddr.sa_len);
+	m->m_len = diskless.root_saddr.sa_len;
+	if (mountnfs(&diskless.root_args, mp, m, "/",
+		diskless.root_hostnam, &vp))
 		panic("nfs root");
 	if (vfs_lock(mp))
 		panic("nfs root2");
--- a/sys/nfs/rpcv2.h	Mon Apr 18 06:15:08 1994 +0000
+++ b/sys/nfs/rpcv2.h	Mon Apr 18 06:18:05 1994 +0000
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)rpcv2.h	7.4 (Berkeley) 6/28/90
- *	$Id: rpcv2.h,v 1.3 1993/05/20 03:19:16 cgd Exp $
+ *	$Id: rpcv2.h,v 1.4 1994/04/18 06:18:23 glass Exp $
  */
 
 #ifndef _NFS_RPCV2_H_
@@ -90,4 +90,8 @@
 #define	RPCMNT_PATHLEN	1024
 #define	RPCPROG_NFS	100003
 
+#ifdef KERNEL
+int krpc_call __P((struct sockaddr *, u_long, u_long, u_long,
+		   struct mbuf **, int));
+#endif		   
 #endif /* !_NFS_RPCV2_H_ */
--- a/sys/nfs/swapnfs.c	Mon Apr 18 06:15:08 1994 +0000
+++ b/sys/nfs/swapnfs.c	Mon Apr 18 06:18:05 1994 +0000
@@ -34,13 +34,12 @@
  * SUCH DAMAGE.
  *
  *	from: @(#)nfsswapvmunix.c	7.1 (Berkeley) 3/4/91
- *	$Id: swapnfs.c,v 1.5 1994/03/01 08:00:02 glass Exp $
+ *	$Id: swapnfs.c,v 1.6 1994/04/18 06:18:24 glass Exp $
  */
 
 /*
- * Sample NFS swapvmunix configuration file.
- * This should be filled in by the bootstrap program.
- * See /sys/nfs/nfsdiskless.h for details of the fields.
+ * NFS parameters are now filled in nfs_mountroot() by
+ * nfs_boot().
  */
 
 #include <sys/param.h>
@@ -50,119 +49,15 @@
 
 #include <net/if.h>
 
-#include <nfs/nfsv2.h>
-#include <nfs/nfsdiskless.h>
-
 dev_t	rootdev = NODEV;
 dev_t	argdev  = NODEV;
 dev_t	dumpdev = NODEV;
 
 struct	swdevt swdevt[] = {
 	{ NODEV, 0, 0 },
-	{ 0, 0, 0 }
+        { 0, 0, 0 }
 };
 
 extern int nfs_mountroot();
-
-/* We start with transfer sizes of 4K during boot			*/
-/* as the WD8003 has problems to support 8K of back to back packets	*/
-struct nfs_diskless nfs_diskless = {
-	{ 0 },		/* myif */
-	{ 0 },		/* mygateway */
-	{		/* swap_args */
-	    0,		/* addr */
-	    0,		/* sotype */
-	    0,		/* proto */
-	    0,		/* fh */
-	    NFSMNT_WSIZE|NFSMNT_RSIZE,	/* flags */
-	    4096,	/* wsize */
-	    4096,	/* rsize */
-	    0,		/* timeo */
-	    0,		/* retrans */
-	    0		/* hostname */
-	},
-	{ 0 },		/* swap_fh */
-	{ 0 },		/* swap_saddr */
-	{ 0 },		/* swap_hostnam */
-	{		/* root_args */
-	    0,		/* addr */
-	    0,		/* sotype */
-	    0,		/* proto */
-	    0,		/* fh */
-	    NFSMNT_WSIZE|NFSMNT_RSIZE,	/* flags */
-	    4096,	/* wsize */
-	    4096,	/* rsize */
-	    0,		/* timeo */
-	    0,		/* retrans */
-	    0		/* hostname */
-	},
-	{ 0 },		/* root_fh */
-	{ 0 },		/* root_saddr */
-	{ 0 }		/* root_hostnam */
-};
-
-#ifndef NFSDISKLESS_HARDWIRE
-
 int (*mountroot)() = nfs_mountroot;
-     
-#else
-
-int nfs_hack_mountroot();
-int (*mountroot)() = nfs_hack_mountroot;
-
-#define NFS_SOCKET 2049
-
-/* this is an egregious hack necessitated by many unfortunate circumstances*/
-
-int nfs_hack_mountroot()
-{
-    struct ifaliasreq diskless_if = {
-	"le0",			/* temporarily */
-	NFSDISKLESS_IF_ADDR,
-	NFSDISKLESS_IF_BADDR,
-	NFSDISKLESS_IF_MASK
-	};
-#ifdef NFSDISKLESS_GATEWAY
-    struct sockaddr diskless_gateway = NFSDISKLESS_GATEWAY;
-#endif
-    u_char diskless_swap_fh[NFS_FHSIZE] = NFSDISKLESS_SWAP_FH;
-    struct sockaddr diskless_swap_saddr = NFSDISKLESS_SWAP_SADDR;
-    u_char diskless_root_fh[NFS_FHSIZE] = NFSDISKLESS_ROOT_FH;
-    struct sockaddr diskless_root_saddr = NFSDISKLESS_ROOT_SADDR;
-    char *diskless_swap_hostnam = "solipsist";
-    char *diskless_root_hostnam = "solipsist";
-
-    nfs_diskless.swap_saddr.sa_data[0] = nfs_diskless.root_saddr.sa_data[0]
-                = NFS_SOCKET >> 8;
-    nfs_diskless.swap_saddr.sa_data[1] = nfs_diskless.root_saddr.sa_data[1]
-                = NFS_SOCKET & 0x00FF;
-    bcopy(&diskless_if, &nfs_diskless.myif, sizeof(diskless_if));
-#ifdef NFSDISKLESS_GATEWAY
-    bcopy(&diskless_gateway, &nfs_diskless.mygateway,
-	  sizeof(diskless_gateway));
-#endif
-    bcopy(&diskless_swap_saddr, &nfs_diskless.swap_saddr,
-	  sizeof(diskless_swap_saddr));
-    bcopy(&diskless_root_saddr, &nfs_diskless.root_saddr,
-	  sizeof(diskless_root_saddr));
-    bcopy(diskless_root_fh, nfs_diskless.root_fh, NFS_FHSIZE);
-    bcopy(diskless_swap_fh, nfs_diskless.swap_fh, NFS_FHSIZE);
-    strcpy(nfs_diskless.swap_hostnam, diskless_swap_hostnam);
-    strcpy(nfs_diskless.root_hostnam, diskless_root_hostnam);
-    nfs_diskless.swap_args.addr = &nfs_diskless.swap_saddr;
-    nfs_diskless.swap_args.fh = (nfsv2fh_t *) nfs_diskless.swap_fh;
-    nfs_diskless.swap_args.sotype = SOCK_DGRAM;
-    nfs_diskless.swap_args.timeo = 10;
-    nfs_diskless.swap_args.retrans = 100;
-    nfs_diskless.swap_args.hostname = nfs_diskless.swap_hostnam;
-    nfs_diskless.root_args.addr = &nfs_diskless.root_saddr;
-    nfs_diskless.root_args.fh = (nfsv2fh_t *) nfs_diskless.root_fh;
-    nfs_diskless.root_args.sotype = SOCK_DGRAM;
-    nfs_diskless.root_args.timeo = 10;
-    nfs_diskless.root_args.retrans = 100;
-    nfs_diskless.root_args.hostname = nfs_diskless.root_hostnam;
-
-    return nfs_mountroot();
-}
-
-#endif     
+