New diskless boot code (uses RARP, bootparamd).

This commit is contained in:
gwr 1994-06-13 15:28:55 +00:00
parent f5ef67b2d1
commit 0784b58d30
4 changed files with 707 additions and 528 deletions

View File

@ -38,7 +38,7 @@
* 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 $
* $Id: krpc_subr.c,v 1.2 1994/06/13 15:28:55 gwr Exp $
*/
#include <sys/param.h>
@ -105,9 +105,17 @@ struct rpc_reply {
#define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */
/*
* What is the longest we will wait before re-sending a request?
* Note this is also the frequency of "RPC timeout" messages.
* The re-send loop count sup linearly to this maximum, so the
* first complaint will happen after (1+2+3+4+5)=15 seconds.
*/
#define MAX_RESEND_DELAY 5 /* seconds */
/*
* 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.
* Returns non-zero error on failure.
*/
int
krpc_portmap(sa, prog, vers, portp)
@ -134,10 +142,11 @@ krpc_portmap(sa, prog, vers, portp)
return 0;
}
m = m_get(M_WAIT, MT_DATA);
m = m_gethdr(M_WAIT, MT_DATA);
if (m == NULL)
return ENOBUFS;
m->m_len = sizeof(*sdata);
m->m_pkthdr.len = m->m_len;
sdata = mtod(m, struct sdata *);
/* Do the RPC to get it. */
@ -146,8 +155,8 @@ krpc_portmap(sa, prog, vers, portp)
sdata->proto = htonl(IPPROTO_UDP);
sdata->port = 0;
error = krpc_call(sa, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
&m, sizeof(*rdata));
error = krpc_call(sa, PMAPPROG, PMAPVERS,
PMAPPROC_GETPORT, &m);
if (error)
return error;
@ -162,11 +171,10 @@ krpc_portmap(sa, prog, vers, portp)
* Do a remote procedure call (RPC) and wait for its reply.
*/
int
krpc_call(sa, prog, vers, func, data, want)
krpc_call(sa, prog, vers, func, data)
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;
@ -224,14 +232,27 @@ krpc_call(sa, prog, vers, func, data, want)
goto out;
/*
* Build the RPC message header.
* Prepend RPC message header.
*/
mhead = m_gethdr(M_WAIT, MT_DATA);
m = *data;
*data = NULL;
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("krpc_call: send data w/o pkthdr");
if (m->m_pkthdr.len < m->m_len)
panic("krpc_call: pkthdr.len not set");
#endif
mhead = m_prepend(m, sizeof(*call), M_WAIT);
if (mhead == NULL) {
error = ENOBUFS;
goto out;
}
mhead->m_len = sizeof(*call);
mhead->m_pkthdr.len += sizeof(*call);
mhead->m_pkthdr.rcvif = NULL;
/*
* Fill in the RPC header
*/
call = mtod(mhead, struct rpc_call *);
bzero((caddr_t)call, sizeof(*call));
call->rp_xid = ++xid; /* no need to put in network order */
@ -244,34 +265,30 @@ krpc_call(sa, prog, vers, func, data, want)
/* 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.
* Send it, repeatedly, until a reply is received,
* but delay each re-send by an increasing amount.
* If the delay hits the maximum, 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)
if (m == NULL) {
error = ENOBUFS;
goto out;
}
error = sosend(so, nam, NULL, m, NULL, 0);
if (error) {
printf("krpc_call: sosend: %d\n", error);
goto out;
}
m = NULL;
/* Determine new timeout (1 to 10) */
if (timo < 10)
/* Determine new timeout. */
if (timo < MAX_RESEND_DELAY)
timo++;
else
printf("RPC timeout for server 0x%X\n",
printf("RPC timeout for server 0x%x\n",
ntohl(sin->sin_addr.s_addr));
/*
@ -310,30 +327,47 @@ krpc_call(sa, prog, vers, func, data, want)
gotreply:
/*
* Got the reply. Check and strip header.
* Make result buffer contiguous.
*/
#ifdef DIAGNOSTIC
if ((m->m_flags & M_PKTHDR) == 0)
panic("krpc_call: received pkt w/o header?");
#endif
len = m->m_pkthdr.len;
if (m->m_len < len) {
m = m_pullup(m, len);
if (m == NULL) {
error = ENOBUFS;
goto out;
}
}
reply = mtod(m, struct rpc_reply *);
/*
* Check RPC acceptance and status.
*/
if (reply->rp_astatus != 0) {
error = reply->rp_u.rpu_errno;
printf("rpc denied, error=%d\n", error);
m_freem(m);
goto out;
}
if ((error = reply->rp_u.rpu_ok.rp_rstatus) != 0) {
printf("rpc status=%d\n", error);
m_freem(m);
goto out;
}
/*
* Strip RPC header
*/
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;
@ -343,5 +377,3 @@ krpc_call(sa, prog, vers, func, data, want)
soclose(so);
return error;
}

View File

@ -10,25 +10,21 @@
* 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
* 3. The name of the authors 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.
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``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 AUTHORS 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.
*
* $Id: nfs_boot.c,v 1.2 1994/05/05 05:39:42 cgd Exp $
* $Id: nfs_boot.c,v 1.3 1994/06/13 15:28:59 gwr Exp $
*/
#include <sys/param.h>
@ -43,7 +39,10 @@
#include <sys/reboot.h>
#include <net/if.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <nfs/rpcv2.h>
#include <nfs/nfsv2.h>
@ -54,347 +53,538 @@
* Support for NFS diskless booting, specifically getting information
* about where to boot from, what pathnames, etc.
*
* We currently support the RPC bootparam protocol.
* This implememtation uses RARP and the bootparam RPC.
* We are forced to implement RPC anyway (to get file handles)
* so we might as well take advantage of it for bootparam too.
*
* We'd like to support BOOTP, but someone needs to write small kernel-ized
* BOOTP client
* The diskless boot sequence goes as follows:
* (1) Get our interface address using RARP
* (also save the address of the RARP server)
* (2) Get our hostname using RPC/bootparam/whoami
* (all boopararms RPCs to the RARP server)
* (3) Get the root path using RPC/bootparam/getfile
* (4) Get the root file handle using RPC/mountd
* (5) Get the swap path using RPC/bootparam/getfile
* (6) Get the swap file handle using RPC/mountd
*
* (This happens to be the way Sun does it too.)
*/
/* from rfc951 to avoid bringing in cmu header file */
/* bootparam RPC */
static int bp_whoami(struct sockaddr_in *bpsin,
struct in_addr *my_ip,
struct in_addr *gw_ip);
static int bp_getfile(struct sockaddr_in *bpsin, char *key,
struct sockaddr_in *mdsin,
char *servname, char *path);
#define UDP_BOOTPSERVER 67
#define UDP_BOOTPCLIENT 68
/* mountd RPC */
static int md_mount(struct sockaddr_in *mdsin, char *path, u_char *fh);
#define BOOTP_REQUEST 1
#define BOOTP_REPLY 2
/* other helpers */
static void get_path_and_handle(struct sockaddr_in *bpsin, char *key,
struct nfs_dlmount *ndmntp);
/* 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.
* Called with an empty nfs_diskless struct to be filled in.
*/
int nfs_boot_init(nd, procp)
struct nfs_diskless *nd;
struct proc *procp;
{
struct ifreq ireq;
struct in_addr my_ip, srv_ip, gw_ip;
struct sockaddr_in bp_sin;
struct sockaddr_in *sin;
struct ifnet *ifp;
struct socket *so;
int error, len;
u_short port;
#if 0
/*
* XXX time must be non-zero when we init the interface or else
* the arp code will wedge... (Fixed in if_ether.c -gwr)
*/
if (time.tv_sec == 0)
time.tv_sec = 1;
#endif
/*
* Find an interface, rarp for its ip address, stuff it, the
* implied broadcast addr, and netmask into a nfs_diskless struct.
*
* This was moved here from nfs_vfsops.c because this procedure
* would be quite different if someone decides to write (i.e.) a
* BOOTP version of this file (might not use RARP, etc.) -gwr
*/
/*
* Find a network interface.
* XXX - This should use the specified boot device.
*/
for (ifp = ifnet; ifp; ifp = ifp->if_next)
if ((ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
break;
if (ifp == NULL)
panic("nfs_boot: no suitable interface");
sprintf(ireq.ifr_name, "%s%d", ifp->if_name, ifp->if_unit);
printf("nfs_boot: using network interface '%s'\n",
ireq.ifr_name);
/*
* Bring up the interface.
*/
if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0)) != 0)
panic("nfs_boot: socreate, error=%d", error);
ireq.ifr_flags = IFF_UP;
error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp);
if (error) panic("nfs_boot: SIFFLAGS, error=%d", error);
/*
* Do RARP for the interface address. Also
* save the server address for bootparam RPC.
*/
if ((error = revarpwhoarewe(ifp, &srv_ip, &my_ip)) != 0)
panic("revarp failed, error=%d", error);
printf("nfs_boot: client=0x%x, server=0x%x\n",
my_ip.s_addr, srv_ip.s_addr);
/*
* Do enough of ifconfig(8) so that the chosen interface can
* talk to the server(s). (also get brcast addr and netmask)
*/
/* Set interface address. */
sin = (struct sockaddr_in *)&ireq.ifr_addr;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = my_ip.s_addr;
error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp);
if (error) panic("nfs_boot: set if addr, error=%d", error);
soclose(so);
/*
* Get client name and gateway address.
* RPC: bootparam/whoami
*/
bp_sin.sin_len = sizeof(bp_sin);
bp_sin.sin_family = AF_INET;
bp_sin.sin_addr.s_addr = srv_ip.s_addr;
hostnamelen = MAXHOSTNAMELEN;
error = bp_whoami(&bp_sin, /* input: where to send RPC */
&my_ip, /* input: client IP */
&gw_ip); /* ouptut: gateway IP */
if (error)
panic("nfs_boot: bootparam whoami, error=%d", error);
printf("nfs_boot: hostname=%s\n", hostname);
#ifdef NFS_BOOT_GATEWAY
/*
* XXX - Server supplied gateway is usually bogus...
* (At least for SunOS 4.1.3 servers it is.)
* If your server is OK, you can turn on this option.
*
* If the gateway address is set, add a default route.
* (The mountd RPCs may go across a gateway.)
*/
if (gw_ip.s_addr) {
/* Destination: (default) */
struct sockaddr_in dst, gw;
bzero(&dst, sizeof(dst));
dst.sin_len = sizeof(dst);
dst.sin_family = AF_INET;
/* Gateway: */
bzero(&gw, sizeof(gw));
gw.sin_len = sizeof(gw);
gw.sin_family = AF_INET;
gw.sin_addr.s_addr = gw_ip.s_addr;
/* Netmask: */
error = ifioctl(so, SIOCGIFNETMASK, (caddr_t)&ireq, procp);
if (error) panic("nfs_boot: get netmask, error=%d", error);
/* add, dest, gw, mask, flags, 0 */
error = rtrequest(RTM_ADD, &dst, &gw, &ifr.ifr_addr,
(RTF_UP | RTF_GATEWAY), NULL);
if (error)
printf("nfs_boot: add route, error=%d\n", error);
}
#endif
get_path_and_handle(&bp_sin, "root", &nd->nd_root);
get_path_and_handle(&bp_sin, "swap", &nd->nd_swap);
return (0);
}
static void
get_path_and_handle(bpsin, key, ndmntp)
struct sockaddr_in *bpsin; /* bootparam server */
char *key; /* root or swap */
struct nfs_dlmount *ndmntp; /* output */
{
char pathname[MAXPATHLEN];
int error;
/*
* Get server:pathname for "key" (root or swap)
* using RPC to bootparam/getfile
*/
error = bp_getfile(bpsin, key,
&ndmntp->ndm_saddr,
ndmntp->ndm_host,
pathname);
if (error)
panic("nfs_boot: bootparam get %s: %d", key, error);
printf("%s on %s:%s\n", key, ndmntp->ndm_host, pathname);
/*
* Get file handle for "key" (root or swap)
* using RPC to mountd/mount
*/
error = md_mount(&ndmntp->ndm_saddr,
pathname,
ndmntp->ndm_fh);
if (error)
panic("nfs_boot: mountd %s, error=%d", key, error);
}
/*
* Get an mbuf with the given length, and
* initialize the pkthdr length field.
*/
static struct mbuf *
m_get_len(int msg_len)
{
struct mbuf *m;
m = m_gethdr(M_WAIT, MT_DATA);
if (m == NULL)
return NULL;
if (msg_len > MHLEN) {
if (msg_len > MCLBYTES)
panic("nfs_boot: msg_len > MCLBYTES");
MCLGET(m, M_WAIT);
if (m == NULL)
return NULL;
}
m->m_len = msg_len;
m->m_pkthdr.len = m->m_len;
return (m);
}
/*
* String representation for RPC.
*/
struct rpc_string {
u_long len; /* length without null or padding */
u_char data[4]; /* data (longer, of course) */
/* data is padded to a long-word boundary */
};
/* Compute space used given string length. */
#define RPC_STR_SIZE(slen) (4 + ((slen + 3) & ~3))
/*
* Inet address in RPC messages
* (Note, really four longs, NOT chars. Blech.)
*/
struct bp_inaddr {
u_long atype;
long addr[4];
};
/*
* 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)
* domain name (domainname)
* gateway address
*
* Setting the hostname and domainname here may be somewhat
* controvercial, but it is so easy to do it here. -gwr
*/
static int
nfs_boot_getfh(sa, path, fhp)
struct sockaddr *sa; /* server address */
bp_whoami(struct sockaddr_in *bpsin,
struct in_addr *my_ip,
struct in_addr *gw_ip)
{
/* The RPC structures */
struct bp_inaddr *bia;
struct rpc_string *str;
struct mbuf *m;
struct sockaddr_in *sin;
int error, msg_len;
int cn_len, dn_len;
u_char *p;
/*
* Get message buffer of sufficient size.
*/
msg_len = sizeof(*bia);
m = m_get_len(msg_len);
if (m == NULL)
return ENOBUFS;
/*
* Build request message.
*/
/* 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++;
/* RPC: bootparam/whoami */
error = krpc_call((struct sockaddr *)bpsin,
BOOTPARAM_PROG, BOOTPARAM_VERS,
BOOTPARAM_WHOAMI, &m);
if (error)
return error;
/*
* Parse result message.
*/
msg_len = m->m_len;
p = mtod(m, char *);
/* client name */
if (msg_len < sizeof(*str))
goto bad;
str = (struct rpc_string *)p;
cn_len = ntohl(str->len);
if (msg_len < cn_len)
goto bad;
if (cn_len >= MAXHOSTNAMELEN)
goto bad;
bcopy(str->data, hostname, cn_len);
hostname[cn_len] = '\0';
hostnamelen = cn_len;
p += RPC_STR_SIZE(cn_len);
msg_len -= RPC_STR_SIZE(cn_len);
/* domain name */
if (msg_len < sizeof(*str))
goto bad;
str = (struct rpc_string *)p;
dn_len = ntohl(str->len);
if (msg_len < dn_len)
goto bad;
if (dn_len >= MAXHOSTNAMELEN)
goto bad;
bcopy(str->data, domainname, dn_len);
domainname[dn_len] = '\0';
domainnamelen = dn_len;
p += RPC_STR_SIZE(dn_len);
msg_len -= RPC_STR_SIZE(dn_len);
/* gateway address */
if (msg_len < sizeof(*bia))
goto bad;
bia = (struct bp_inaddr *)p;
if (bia->atype != htonl(1))
goto bad;
p = (u_char*)gw_ip;
*p++ = ntohl(bia->addr[0]);
*p++ = ntohl(bia->addr[1]);
*p++ = ntohl(bia->addr[2]);
*p++ = ntohl(bia->addr[3]);
goto out;
bad:
printf("nfs_boot: bootparam_whoami: bad reply\n");
error = EBADRPC;
out:
m_freem(m);
return(error);
}
/*
* RPC: bootparam/getfile
* Given client name and file "key", get:
* server name
* server IP address
* server pathname
*/
static int
bp_getfile(struct sockaddr_in *bpsin, char *key,
struct sockaddr_in *md_sin, char *serv_name, char *pathname)
{
struct rpc_string *str;
struct mbuf *m;
struct bp_inaddr *bia;
struct sockaddr_in *sin;
u_char *p, *q;
int error, msg_len;
int cn_len, key_len, sn_len, path_len;
/*
* Get message buffer of sufficient size.
*/
cn_len = hostnamelen;
key_len = strlen(key);
msg_len = 0;
msg_len += RPC_STR_SIZE(cn_len);
msg_len += RPC_STR_SIZE(key_len);
m = m_get_len(msg_len);
if (m == NULL)
return ENOBUFS;
/*
* Build request message.
*/
p = mtod(m, u_char *);
bzero(p, msg_len);
/* client name (hostname) */
str = (struct rpc_string *)p;
str->len = htonl(cn_len);
bcopy(hostname, str->data, cn_len);
p += RPC_STR_SIZE(cn_len);
/* key name (root or swap) */
str = (struct rpc_string *)p;
str->len = htonl(key_len);
bcopy(key, str->data, key_len);
/* RPC: bootparam/getfile */
error = krpc_call((struct sockaddr *)bpsin,
BOOTPARAM_PROG, BOOTPARAM_VERS,
BOOTPARAM_GETFILE, &m);
if (error)
return error;
/*
* Parse result message.
*/
p = mtod(m, u_char *);
msg_len = m->m_len;
/* server name */
if (msg_len < sizeof(*str))
goto bad;
str = (struct rpc_string *)p;
sn_len = ntohl(str->len);
if (msg_len < sn_len)
goto bad;
if (sn_len >= MNAMELEN)
goto bad;
bcopy(str->data, serv_name, sn_len);
serv_name[sn_len] = '\0';
p += RPC_STR_SIZE(sn_len);
msg_len -= RPC_STR_SIZE(sn_len);
/* server IP address (mountd) */
if (msg_len < sizeof(*bia))
goto bad;
bia = (struct bp_inaddr *)p;
if (bia->atype != htonl(1))
goto bad;
sin = md_sin;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
q = (u_char*) &sin->sin_addr;
*q++ = ntohl(bia->addr[0]);
*q++ = ntohl(bia->addr[1]);
*q++ = ntohl(bia->addr[2]);
*q++ = ntohl(bia->addr[3]);
p += sizeof(*bia);
msg_len -= sizeof(*bia);
/* server pathname */
if (msg_len < sizeof(*str))
goto bad;
str = (struct rpc_string *)p;
path_len = ntohl(str->len);
if (msg_len < path_len)
goto bad;
if (path_len >= MAXPATHLEN)
goto bad;
bcopy(str->data, pathname, path_len);
pathname[path_len] = '\0';
goto out;
bad:
printf("nfs_boot: bootparam_getfile: bad reply\n");
error = EBADRPC;
out:
m_freem(m);
return(0);
}
/*
* RPC: mountd/mount
* Given a server pathname, get an NFS file handle.
* Also, sets sin->sin_port to the NFS service port.
*/
static int
md_mount(mdsin, path, fhp)
struct sockaddr_in *mdsin; /* mountd server address */
char *path;
u_char *fhp;
{
/* The RPC structures */
struct sdata {
u_long len;
u_char path[4]; /* longer, of course */
} *sdata;
struct rpc_string *str;
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 ??? */
mlen = RPC_STR_SIZE(slen);
m = m_get(M_WAIT, MT_DATA);
m = m_get_len(mlen);
if (m == NULL)
return ENOBUFS;
m->m_len = mlen;
sdata = mtod(m, struct sdata *);
sdata->len = htonl(slen);
bcopy(path, sdata->path, slen);
str = mtod(m, struct rpc_string *);
str->len = htonl(slen);
bcopy(path, str->data, slen);
/* Do RPC to mountd. */
error = krpc_call(sa, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
&m, sizeof(*rdata));
error = krpc_call((struct sockaddr *)mdsin,
RPCPROG_MNT, RPCMNT_VER1,
RPCMNT_MOUNT, &m);
if (error)
return error;
return error; /* message already freed */
mlen = m->m_len;
if (mlen < sizeof(*rdata))
goto bad;
rdata = mtod(m, struct rdata *);
error = ntohl(rdata->errno);
if (!error)
bcopy(rdata->fh, fhp, NFS_FHSIZE);
if (error)
goto bad;
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);
goto out;
bad:
error = EBADRPC;
out:
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;
}

View File

@ -34,7 +34,7 @@
* SUCH DAMAGE.
*
* from: @(#)nfs_vfsops.c 8.3 (Berkeley) 1/4/94
* $Id: nfs_vfsops.c,v 1.21 1994/06/08 11:37:03 mycroft Exp $
* $Id: nfs_vfsops.c,v 1.22 1994/06/13 15:29:01 gwr Exp $
*/
#include <sys/param.h>
@ -83,19 +83,12 @@ struct vfsops nfs_vfsops = {
nfs_init,
};
/*
* This structure must be filled in by a primary bootstrap or bootstrap
* server for a diskless/dataless machine. It is initialized below just
* to ensure that it is allocated to initialized data (.data not .bss).
*/
struct nfs_diskless nfs_diskless = { 0 };
extern u_long nfs_procids[NFS_NPROCS];
extern u_long nfs_prog, nfs_vers;
void nfs_disconnect __P((struct nfsmount *));
void nfsargs_ntoh __P((struct nfs_args *));
static struct mount *nfs_mountdiskless __P((char *, char *, int,
struct sockaddr_in *, struct nfs_args *, register struct vnode **));
static struct mount *
nfs_mount_diskless __P((struct nfs_dlmount *, char *, int, struct vnode **));
#define TRUE 1
#define FALSE 0
@ -163,14 +156,9 @@ nfs_statfs(mp, sbp, p)
}
/*
* 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.
* Mount a remote root fs via. NFS. It goes like this:
* - Call nfs_boot_init() to fill in the nfs_diskless struct
* (using RARP, bootparam RPC, mountd RPC)
* - hand craft the swap nfs vnode hanging off a fake mount point
* if swdevt[0].sw_dev == NODEV
* - build the rootfs mount point and call mountnfs() to do the rest.
@ -178,88 +166,32 @@ nfs_statfs(mp, sbp, p)
int
nfs_mountroot()
{
register struct mount *mp;
register struct nfs_diskless *nd = &nfs_diskless;
struct socket *so;
struct nfs_diskless nd;
struct vattr attr;
struct mount *mp;
struct vnode *vp;
struct proc *p = curproc; /* XXX */
int error, i;
struct proc *procp;
struct ucred *cred;
long n;
int error;
procp = curproc; /* XXX */
/*
* XXX time must be non-zero when we init the interface or else
* the arp code will wedge...
* Call nfs_boot_init() to fill in the nfs_diskless struct.
* Side effect: Finds and configures a network interface.
*/
if (time.tv_sec == 0)
time.tv_sec = 1;
#ifdef notyet
/* Set up swap credentials. */
proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
NGROUPS)
proc0.p_ucred->cr_ngroups = NGROUPS;
for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
#endif
bzero((caddr_t) &nd, sizeof(nd));
nfs_boot_init(&nd, procp);
/*
* Do enough of ifconfig(8) so that the critical net interface can
* talk to the server.
* Create the root mount point.
*/
if (error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
panic("nfs_mountroot: socreate: %d", error);
if (error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p))
panic("nfs_mountroot: SIOCAIFADDR: %d", error);
soclose(so);
mp = nfs_mount_diskless(&nd.nd_root, "/", MNT_RDONLY, &vp);
/*
* If the gateway field is filled in, set it as the default route.
* Link it into the mount list.
*/
if (nd->mygateway.sin_len != 0) {
struct sockaddr_in mask, sin;
bzero((caddr_t)&mask, sizeof(mask));
sin = mask;
sin.sin_family = AF_INET;
sin.sin_len = sizeof(sin);
if (error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
(struct sockaddr *)&nd->mygateway,
(struct sockaddr *)&mask,
RTF_UP | RTF_GATEWAY, (struct rtentry **)0))
panic("nfs_mountroot: RTM_ADD: %d", error);
}
/*
* If swapping to an nfs node (indicated by swdevt[0].sw_dev == NODEV):
* Create a fake mount point just for the swap vnode so that the
* swap file can be on a different server from the rootfs.
*/
if (swdevt[0].sw_dev == NODEV) {
nd->swap_args.fh = (nfsv2fh_t *)nd->swap_fh;
(void) nfs_mountdiskless(nd->swap_hostnam, "/swap", 0,
&nd->swap_saddr, &nd->swap_args, &vp);
/*
* Since the swap file is not the root dir of a file system,
* hack it to a regular file.
*/
vp->v_type = VREG;
vp->v_flag = 0;
swapdev_vp = vp;
VREF(vp);
swdevt[0].sw_vp = vp;
swdevt[0].sw_nblks = ntohl(nd->swap_nblks);
} else if (bdevvp(swapdev, &swapdev_vp))
panic("nfs_mountroot: can't setup swapdev_vp");
/*
* Create the rootfs mount point.
*/
nd->root_args.fh = (nfsv2fh_t *)nd->root_fh;
mp = nfs_mountdiskless(nd->root_hostnam, "/", MNT_RDONLY,
&nd->root_saddr, &nd->root_args, &vp);
if (vfs_lock(mp))
panic("nfs_mountroot: vfs_lock");
TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
@ -268,18 +200,64 @@ nfs_mountroot()
vfs_unlock(mp);
rootvp = vp;
/* Get root attributes (for the time). */
error = VOP_GETATTR(vp, &attr, procp->p_cred->pc_ucred, procp);
if (error) panic("nfs_mountroot: getattr for root");
n = attr.va_mtime.ts_sec; /* XXX - Always zero. Why? -gwr */
printf(" root time: 0x%x\n", n);
inittodr(n);
#ifdef notyet
/* Set up swap credentials. */
proc0.p_ucred->cr_uid = ntohl(nd.swap_ucred.cr_uid);
proc0.p_ucred->cr_gid = ntohl(nd.swap_ucred.cr_gid);
if ((proc0.p_ucred->cr_ngroups = ntohs(nd.swap_ucred.cr_ngroups)) >
NGROUPS)
proc0.p_ucred->cr_ngroups = NGROUPS;
for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
proc0.p_ucred->cr_groups[i] = ntohl(nd.swap_ucred.cr_groups[i]);
#endif
/*
* This is not really an nfs issue, but it is much easier to
* set hostname here and then let the "/etc/rc.xxx" files
* mount the right /var based upon its preset value.
* "Mount" the swap device.
*
* On a "dataless" configuration (swap on disk) we will have:
* (swdevt[0].sw_dev != NODEV) identifying the swap device.
*/
bcopy(nd->my_hostnam, hostname, MAXHOSTNAMELEN);
hostname[MAXHOSTNAMELEN - 1] = '\0';
for (i = 0; i < MAXHOSTNAMELEN; i++)
if (hostname[i] == '\0')
break;
hostnamelen = i;
inittodr(ntohl(nd->root_time));
if (swdevt[0].sw_dev != NODEV) {
if (bdevvp(swapdev, &swapdev_vp))
panic("nfs_mountroot: can't get swap vp for dev %d,%d",
major(swdevt[0].sw_dev), minor(swdevt[0].sw_dev));
return (0);
}
/*
* If swapping to an nfs node: (swdevt[0].sw_dev == NODEV)
* Create a fake mount point just for the swap vnode so that the
* swap file can be on a different server from the rootfs.
*/
mp = nfs_mount_diskless(&nd.nd_swap, "/swap", 0, &vp);
/*
* Since the swap file is not the root dir of a file system,
* hack it to a regular file.
*/
vp->v_type = VREG;
vp->v_flag = 0;
swapdev_vp = vp;
VREF(vp);
swdevt[0].sw_vp = vp;
/*
* Find out how large the swap file is.
*/
error = VOP_GETATTR(vp, &attr, procp->p_cred->pc_ucred, procp);
if (error) panic("nfs_mountroot: getattr for swap");
n = (long) (attr.va_size / DEV_BSIZE);
printf(" swap size: 0x%x (blocks)\n", n); /* XXX */
swdevt[0].sw_nblks = n;
return (0);
}
@ -287,60 +265,47 @@ nfs_mountroot()
* Internal version of mount system call for diskless setup.
*/
static struct mount *
nfs_mountdiskless(path, which, mountflag, sin, args, vpp)
char *path;
char *which;
int mountflag;
struct sockaddr_in *sin;
struct nfs_args *args;
register struct vnode **vpp;
nfs_mount_diskless(ndmntp, mntname, mntflag, vpp)
struct nfs_dlmount *ndmntp;
char *mntname;
int mntflag;
struct vnode **vpp;
{
register struct mount *mp;
register struct mbuf *m;
register int error;
struct nfs_args args;
struct mount *mp;
struct mbuf *m;
int error;
/* Create the mount point. */
mp = (struct mount *)malloc((u_long)sizeof(struct mount),
M_MOUNT, M_NOWAIT);
if (mp == NULL)
panic("nfs_mountroot: %s mount malloc", which);
panic("nfs_mountroot: malloc mount for %s", mntname);
bzero((char *)mp, (u_long)sizeof(struct mount));
mp->mnt_op = &nfs_vfsops;
mp->mnt_flag = mountflag;
mp->mnt_flag = mntflag;
/* Initialize mount args. */
bzero((caddr_t) &args, sizeof(args));
args.addr = (struct sockaddr *)&ndmntp->ndm_saddr;
args.addrlen = args.addr->sa_len;
args.sotype = SOCK_DGRAM;
args.fh = (nfsv2fh_t *)ndmntp->ndm_fh;
args.hostname = ndmntp->ndm_host;
/* Get mbuf for server sockaddr. */
MGET(m, MT_SONAME, M_DONTWAIT);
if (m == NULL)
panic("nfs_mountroot: %s mount mbuf", which);
bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
m->m_len = sin->sin_len;
nfsargs_ntoh(args);
if (error = mountnfs(args, mp, m, which, path, vpp))
panic("nfs_mountroot: mount %s on %s: %d", path, which, error);
panic("nfs_mountroot: mget soname for %s", mntname);
bcopy((caddr_t)args.addr, mtod(m, caddr_t),
(m->m_len = args.addr->sa_len));
if (error = mountnfs(&args, mp, m, mntname, args.hostname, vpp))
panic("nfs_mountroot: mount %s failed: %d", mntname);
return (mp);
}
/*
* Convert the integer fields of the nfs_args structure from net byte order
* to host byte order. Called by nfs_mountroot() above.
*/
void
nfsargs_ntoh(nfsp)
register struct nfs_args *nfsp;
{
NTOHL(nfsp->sotype);
NTOHL(nfsp->proto);
NTOHL(nfsp->flags);
NTOHL(nfsp->wsize);
NTOHL(nfsp->rsize);
NTOHL(nfsp->timeo);
NTOHL(nfsp->retrans);
NTOHL(nfsp->maxgrouplist);
NTOHL(nfsp->readahead);
NTOHL(nfsp->leaseterm);
NTOHL(nfsp->deadthresh);
}
void
nfs_decode_args(nmp, argp)
struct nfsmount *nmp;

View File

@ -34,34 +34,26 @@
* SUCH DAMAGE.
*
* from: @(#)nfsdiskless.h 8.1 (Berkeley) 6/10/93
* $Id: nfsdiskless.h,v 1.5 1994/06/08 11:37:07 mycroft Exp $
* $Id: nfsdiskless.h,v 1.6 1994/06/13 15:29:04 gwr Exp $
*/
/*
* Structure that must be initialized for a diskless nfs client.
* This structure is used by nfs_mountroot() to set up the root and swap
* vnodes plus do a partial ifconfig(8) and route(8) so that the critical net
* interface can communicate with the server.
* The primary bootstrap is expected to fill in the appropriate fields before
* starting vmunix. Whether or not the swap area is nfs mounted is determined
* vnodes plus do a partial ifconfig(8) and route(8) so that the critical
* net interface can communicate with the server.
* Whether or not the swap area is nfs mounted is determined
* by the value in swdevt[0]. (equal to NODEV --> swap over nfs)
* Currently only works for AF_INET protocols.
* NB: All fields are stored in net byte order to avoid hassles with
* client/server byte ordering differences.
*/
struct nfs_diskless {
struct ifaliasreq myif; /* Default interface */
struct sockaddr_in mygateway; /* Default gateway */
struct nfs_args swap_args; /* Mount args for swap file */
u_char swap_fh[NFS_FHSIZE]; /* Swap file's file handle */
struct sockaddr_in swap_saddr; /* Address of swap server */
char swap_hostnam[MNAMELEN]; /* Host name for mount pt */
int swap_nblks; /* Size of server swap file */
struct ucred swap_ucred; /* Swap credentials */
struct nfs_args root_args; /* Mount args for root fs */
u_char root_fh[NFS_FHSIZE]; /* File handle of root dir */
struct sockaddr_in root_saddr; /* Address of root server */
char root_hostnam[MNAMELEN]; /* Host name for mount pt */
long root_time; /* Timestamp of root fs */
char my_hostnam[MAXHOSTNAMELEN]; /* Client host name */
struct nfs_dlmount {
struct sockaddr_in ndm_saddr; /* Address of file server */
char ndm_host[MNAMELEN]; /* Host name for mount pt */
u_char ndm_fh[NFS_FHSIZE]; /* The file's file handle */
};
struct nfs_diskless {
struct nfs_dlmount nd_root; /* Mount info for root */
struct nfs_dlmount nd_swap; /* Mount info for swap */
};