New diskless boot code (uses RARP, bootparamd).
This commit is contained in:
parent
f5ef67b2d1
commit
0784b58d30
|
@ -38,7 +38,7 @@
|
||||||
* partially based on:
|
* partially based on:
|
||||||
* libnetboot/rpc.c
|
* libnetboot/rpc.c
|
||||||
* @(#) Header: rpc.c,v 1.12 93/09/28 08:31:56 leres Exp (LBL)
|
* @(#) 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>
|
#include <sys/param.h>
|
||||||
|
@ -105,9 +105,17 @@ struct rpc_reply {
|
||||||
|
|
||||||
#define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */
|
#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
|
* 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
|
int
|
||||||
krpc_portmap(sa, prog, vers, portp)
|
krpc_portmap(sa, prog, vers, portp)
|
||||||
|
@ -134,10 +142,11 @@ krpc_portmap(sa, prog, vers, portp)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
m = m_get(M_WAIT, MT_DATA);
|
m = m_gethdr(M_WAIT, MT_DATA);
|
||||||
if (m == NULL)
|
if (m == NULL)
|
||||||
return ENOBUFS;
|
return ENOBUFS;
|
||||||
m->m_len = sizeof(*sdata);
|
m->m_len = sizeof(*sdata);
|
||||||
|
m->m_pkthdr.len = m->m_len;
|
||||||
sdata = mtod(m, struct sdata *);
|
sdata = mtod(m, struct sdata *);
|
||||||
|
|
||||||
/* Do the RPC to get it. */
|
/* Do the RPC to get it. */
|
||||||
|
@ -146,8 +155,8 @@ krpc_portmap(sa, prog, vers, portp)
|
||||||
sdata->proto = htonl(IPPROTO_UDP);
|
sdata->proto = htonl(IPPROTO_UDP);
|
||||||
sdata->port = 0;
|
sdata->port = 0;
|
||||||
|
|
||||||
error = krpc_call(sa, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT,
|
error = krpc_call(sa, PMAPPROG, PMAPVERS,
|
||||||
&m, sizeof(*rdata));
|
PMAPPROC_GETPORT, &m);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
@ -162,11 +171,10 @@ krpc_portmap(sa, prog, vers, portp)
|
||||||
* Do a remote procedure call (RPC) and wait for its reply.
|
* Do a remote procedure call (RPC) and wait for its reply.
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
krpc_call(sa, prog, vers, func, data, want)
|
krpc_call(sa, prog, vers, func, data)
|
||||||
struct sockaddr *sa;
|
struct sockaddr *sa;
|
||||||
u_long prog, vers, func;
|
u_long prog, vers, func;
|
||||||
struct mbuf **data; /* input/output */
|
struct mbuf **data; /* input/output */
|
||||||
int want; /* required response data length */
|
|
||||||
{
|
{
|
||||||
struct socket *so;
|
struct socket *so;
|
||||||
struct sockaddr_in *sin;
|
struct sockaddr_in *sin;
|
||||||
|
@ -224,14 +232,27 @@ krpc_call(sa, prog, vers, func, data, want)
|
||||||
goto out;
|
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) {
|
if (mhead == NULL) {
|
||||||
error = ENOBUFS;
|
error = ENOBUFS;
|
||||||
goto out;
|
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 *);
|
call = mtod(mhead, struct rpc_call *);
|
||||||
bzero((caddr_t)call, sizeof(*call));
|
bzero((caddr_t)call, sizeof(*call));
|
||||||
call->rp_xid = ++xid; /* no need to put in network order */
|
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; */
|
/* call->rp_verf = 0; */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepend RPC header and setup packet header.
|
* Send it, repeatedly, until a reply is received,
|
||||||
*/
|
* but delay each re-send by an increasing amount.
|
||||||
for (len = 0, m = *data; m ; m = m->m_next)
|
* If the delay hits the maximum, start complaining.
|
||||||
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;
|
timo = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* Send RPC request (or re-send). */
|
/* Send RPC request (or re-send). */
|
||||||
m = m_copym(mhead, 0, M_COPYALL, M_WAIT);
|
m = m_copym(mhead, 0, M_COPYALL, M_WAIT);
|
||||||
error = sosend(so, nam, NULL, m, NULL, 0);
|
if (m == NULL) {
|
||||||
if (error)
|
error = ENOBUFS;
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
error = sosend(so, nam, NULL, m, NULL, 0);
|
||||||
|
if (error) {
|
||||||
|
printf("krpc_call: sosend: %d\n", error);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
m = NULL;
|
m = NULL;
|
||||||
|
|
||||||
/* Determine new timeout (1 to 10) */
|
/* Determine new timeout. */
|
||||||
if (timo < 10)
|
if (timo < MAX_RESEND_DELAY)
|
||||||
timo++;
|
timo++;
|
||||||
else
|
else
|
||||||
printf("RPC timeout for server 0x%X\n",
|
printf("RPC timeout for server 0x%x\n",
|
||||||
ntohl(sin->sin_addr.s_addr));
|
ntohl(sin->sin_addr.s_addr));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -310,30 +327,47 @@ krpc_call(sa, prog, vers, func, data, want)
|
||||||
gotreply:
|
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) {
|
if (reply->rp_astatus != 0) {
|
||||||
error = reply->rp_u.rpu_errno;
|
error = reply->rp_u.rpu_errno;
|
||||||
|
printf("rpc denied, error=%d\n", error);
|
||||||
m_freem(m);
|
m_freem(m);
|
||||||
goto out;
|
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);
|
len = sizeof(*reply);
|
||||||
if (reply->rp_u.rpu_ok.rp_auth.rp_atype != 0) {
|
if (reply->rp_u.rpu_ok.rp_auth.rp_atype != 0) {
|
||||||
len += ntohl(reply->rp_u.rpu_ok.rp_auth.rp_alen);
|
len += ntohl(reply->rp_u.rpu_ok.rp_auth.rp_alen);
|
||||||
len = (len + 3) & ~3; /* XXX? */
|
len = (len + 3) & ~3; /* XXX? */
|
||||||
}
|
}
|
||||||
m_adj(m, len);
|
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 */
|
/* result */
|
||||||
*data = m;
|
*data = m;
|
||||||
|
|
||||||
|
@ -343,5 +377,3 @@ krpc_call(sa, prog, vers, func, data, want)
|
||||||
soclose(so);
|
soclose(so);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -10,25 +10,21 @@
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
* documentation and/or other materials provided with the distribution.
|
* documentation and/or other materials provided with the distribution.
|
||||||
* 3. All advertising materials mentioning features or use of this software
|
* 3. The name of the authors may not be used to endorse or promote products
|
||||||
* 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.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
|
||||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL Adam Glass BE LIABLE
|
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* 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>
|
#include <sys/param.h>
|
||||||
|
@ -43,7 +39,10 @@
|
||||||
#include <sys/reboot.h>
|
#include <sys/reboot.h>
|
||||||
|
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
#include <net/route.h>
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/if_ether.h>
|
||||||
|
|
||||||
#include <nfs/rpcv2.h>
|
#include <nfs/rpcv2.h>
|
||||||
#include <nfs/nfsv2.h>
|
#include <nfs/nfsv2.h>
|
||||||
|
@ -54,347 +53,538 @@
|
||||||
* Support for NFS diskless booting, specifically getting information
|
* Support for NFS diskless booting, specifically getting information
|
||||||
* about where to boot from, what pathnames, etc.
|
* 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
|
* The diskless boot sequence goes as follows:
|
||||||
* BOOTP client
|
* (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
|
/* mountd RPC */
|
||||||
#define UDP_BOOTPCLIENT 68
|
static int md_mount(struct sockaddr_in *mdsin, char *path, u_char *fh);
|
||||||
|
|
||||||
#define BOOTP_REQUEST 1
|
/* other helpers */
|
||||||
#define BOOTP_REPLY 2
|
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
|
static int
|
||||||
nfs_boot_getfh(sa, path, fhp)
|
bp_whoami(struct sockaddr_in *bpsin,
|
||||||
struct sockaddr *sa; /* server address */
|
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;
|
char *path;
|
||||||
u_char *fhp;
|
u_char *fhp;
|
||||||
{
|
{
|
||||||
/* The RPC structures */
|
/* The RPC structures */
|
||||||
struct sdata {
|
struct rpc_string *str;
|
||||||
u_long len;
|
|
||||||
u_char path[4]; /* longer, of course */
|
|
||||||
} *sdata;
|
|
||||||
struct rdata {
|
struct rdata {
|
||||||
u_long errno;
|
u_long errno;
|
||||||
u_char fh[NFS_FHSIZE];
|
u_char fh[NFS_FHSIZE];
|
||||||
} *rdata;
|
} *rdata;
|
||||||
struct sockaddr_in *sin;
|
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
int error, mlen, slen;
|
int error, mlen, slen;
|
||||||
|
|
||||||
/*
|
|
||||||
* Validate address family.
|
|
||||||
* Sorry, this is INET specific...
|
|
||||||
*/
|
|
||||||
if (sa->sa_family != AF_INET)
|
|
||||||
return EAFNOSUPPORT;
|
|
||||||
|
|
||||||
slen = strlen(path);
|
slen = strlen(path);
|
||||||
if (slen > (MLEN-4))
|
mlen = RPC_STR_SIZE(slen);
|
||||||
slen = (MLEN-4);
|
|
||||||
mlen = 4 + ((slen + 3) & ~3); /* XXX ??? */
|
|
||||||
|
|
||||||
m = m_get(M_WAIT, MT_DATA);
|
m = m_get_len(mlen);
|
||||||
if (m == NULL)
|
if (m == NULL)
|
||||||
return ENOBUFS;
|
return ENOBUFS;
|
||||||
m->m_len = mlen;
|
str = mtod(m, struct rpc_string *);
|
||||||
sdata = mtod(m, struct sdata *);
|
str->len = htonl(slen);
|
||||||
sdata->len = htonl(slen);
|
bcopy(path, str->data, slen);
|
||||||
bcopy(path, sdata->path, slen);
|
|
||||||
|
|
||||||
/* Do RPC to mountd. */
|
/* Do RPC to mountd. */
|
||||||
error = krpc_call(sa, RPCPROG_MNT, RPCMNT_VER1, RPCMNT_MOUNT,
|
error = krpc_call((struct sockaddr *)mdsin,
|
||||||
&m, sizeof(*rdata));
|
RPCPROG_MNT, RPCMNT_VER1,
|
||||||
|
RPCMNT_MOUNT, &m);
|
||||||
if (error)
|
if (error)
|
||||||
return error;
|
return error; /* message already freed */
|
||||||
|
|
||||||
|
mlen = m->m_len;
|
||||||
|
if (mlen < sizeof(*rdata))
|
||||||
|
goto bad;
|
||||||
rdata = mtod(m, struct rdata *);
|
rdata = mtod(m, struct rdata *);
|
||||||
error = ntohl(rdata->errno);
|
error = ntohl(rdata->errno);
|
||||||
if (!error)
|
if (error)
|
||||||
|
goto bad;
|
||||||
bcopy(rdata->fh, fhp, NFS_FHSIZE);
|
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);
|
m_freem(m);
|
||||||
return error;
|
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* from: @(#)nfs_vfsops.c 8.3 (Berkeley) 1/4/94
|
* 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>
|
#include <sys/param.h>
|
||||||
|
@ -83,19 +83,12 @@ struct vfsops nfs_vfsops = {
|
||||||
nfs_init,
|
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_procids[NFS_NPROCS];
|
||||||
extern u_long nfs_prog, nfs_vers;
|
extern u_long nfs_prog, nfs_vers;
|
||||||
void nfs_disconnect __P((struct nfsmount *));
|
void nfs_disconnect __P((struct nfsmount *));
|
||||||
void nfsargs_ntoh __P((struct nfs_args *));
|
|
||||||
static struct mount *nfs_mountdiskless __P((char *, char *, int,
|
static struct mount *
|
||||||
struct sockaddr_in *, struct nfs_args *, register struct vnode **));
|
nfs_mount_diskless __P((struct nfs_dlmount *, char *, int, struct vnode **));
|
||||||
|
|
||||||
#define TRUE 1
|
#define TRUE 1
|
||||||
#define FALSE 0
|
#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
|
* Mount a remote root fs via. NFS. It goes like this:
|
||||||
* nfs_diskless structure that has been filled in properly by some primary
|
* - Call nfs_boot_init() to fill in the nfs_diskless struct
|
||||||
* bootstrap.
|
* (using RARP, bootparam RPC, mountd RPC)
|
||||||
* 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.
|
|
||||||
* - hand craft the swap nfs vnode hanging off a fake mount point
|
* - hand craft the swap nfs vnode hanging off a fake mount point
|
||||||
* if swdevt[0].sw_dev == NODEV
|
* if swdevt[0].sw_dev == NODEV
|
||||||
* - build the rootfs mount point and call mountnfs() to do the rest.
|
* - build the rootfs mount point and call mountnfs() to do the rest.
|
||||||
|
@ -178,67 +166,78 @@ nfs_statfs(mp, sbp, p)
|
||||||
int
|
int
|
||||||
nfs_mountroot()
|
nfs_mountroot()
|
||||||
{
|
{
|
||||||
register struct mount *mp;
|
struct nfs_diskless nd;
|
||||||
register struct nfs_diskless *nd = &nfs_diskless;
|
struct vattr attr;
|
||||||
struct socket *so;
|
struct mount *mp;
|
||||||
struct vnode *vp;
|
struct vnode *vp;
|
||||||
struct proc *p = curproc; /* XXX */
|
struct proc *procp;
|
||||||
int error, i;
|
struct ucred *cred;
|
||||||
|
long n;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
procp = curproc; /* XXX */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX time must be non-zero when we init the interface or else
|
* Call nfs_boot_init() to fill in the nfs_diskless struct.
|
||||||
* the arp code will wedge...
|
* Side effect: Finds and configures a network interface.
|
||||||
*/
|
*/
|
||||||
if (time.tv_sec == 0)
|
bzero((caddr_t) &nd, sizeof(nd));
|
||||||
time.tv_sec = 1;
|
nfs_boot_init(&nd, procp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create the root mount point.
|
||||||
|
*/
|
||||||
|
mp = nfs_mount_diskless(&nd.nd_root, "/", MNT_RDONLY, &vp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Link it into the mount list.
|
||||||
|
*/
|
||||||
|
if (vfs_lock(mp))
|
||||||
|
panic("nfs_mountroot: vfs_lock");
|
||||||
|
TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
|
||||||
|
mp->mnt_flag |= MNT_ROOTFS;
|
||||||
|
mp->mnt_vnodecovered = NULLVP;
|
||||||
|
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
|
#ifdef notyet
|
||||||
/* Set up swap credentials. */
|
/* Set up swap credentials. */
|
||||||
proc0.p_ucred->cr_uid = ntohl(nd->swap_ucred.cr_uid);
|
proc0.p_ucred->cr_uid = ntohl(nd.swap_ucred.cr_uid);
|
||||||
proc0.p_ucred->cr_gid = ntohl(nd->swap_ucred.cr_gid);
|
proc0.p_ucred->cr_gid = ntohl(nd.swap_ucred.cr_gid);
|
||||||
if ((proc0.p_ucred->cr_ngroups = ntohs(nd->swap_ucred.cr_ngroups)) >
|
if ((proc0.p_ucred->cr_ngroups = ntohs(nd.swap_ucred.cr_ngroups)) >
|
||||||
NGROUPS)
|
NGROUPS)
|
||||||
proc0.p_ucred->cr_ngroups = NGROUPS;
|
proc0.p_ucred->cr_ngroups = NGROUPS;
|
||||||
for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
|
for (i = 0; i < proc0.p_ucred->cr_ngroups; i++)
|
||||||
proc0.p_ucred->cr_groups[i] = ntohl(nd->swap_ucred.cr_groups[i]);
|
proc0.p_ucred->cr_groups[i] = ntohl(nd.swap_ucred.cr_groups[i]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do enough of ifconfig(8) so that the critical net interface can
|
* "Mount" the swap device.
|
||||||
* talk to the server.
|
*
|
||||||
|
* On a "dataless" configuration (swap on disk) we will have:
|
||||||
|
* (swdevt[0].sw_dev != NODEV) identifying the swap device.
|
||||||
*/
|
*/
|
||||||
if (error = socreate(nd->myif.ifra_addr.sa_family, &so, SOCK_DGRAM, 0))
|
if (swdevt[0].sw_dev != NODEV) {
|
||||||
panic("nfs_mountroot: socreate: %d", error);
|
if (bdevvp(swapdev, &swapdev_vp))
|
||||||
if (error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, p))
|
panic("nfs_mountroot: can't get swap vp for dev %d,%d",
|
||||||
panic("nfs_mountroot: SIOCAIFADDR: %d", error);
|
major(swdevt[0].sw_dev), minor(swdevt[0].sw_dev));
|
||||||
soclose(so);
|
return (0);
|
||||||
|
|
||||||
/*
|
|
||||||
* If the gateway field is filled in, set it as the default route.
|
|
||||||
*/
|
|
||||||
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):
|
* If swapping to an nfs node: (swdevt[0].sw_dev == NODEV)
|
||||||
* Create a fake mount point just for the swap vnode so that the
|
* Create a fake mount point just for the swap vnode so that the
|
||||||
* swap file can be on a different server from the rootfs.
|
* swap file can be on a different server from the rootfs.
|
||||||
*/
|
*/
|
||||||
if (swdevt[0].sw_dev == NODEV) {
|
mp = nfs_mount_diskless(&nd.nd_swap, "/swap", 0, &vp);
|
||||||
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,
|
* Since the swap file is not the root dir of a file system,
|
||||||
|
@ -249,37 +248,16 @@ nfs_mountroot()
|
||||||
swapdev_vp = vp;
|
swapdev_vp = vp;
|
||||||
VREF(vp);
|
VREF(vp);
|
||||||
swdevt[0].sw_vp = 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.
|
* Find out how large the swap file is.
|
||||||
*/
|
*/
|
||||||
nd->root_args.fh = (nfsv2fh_t *)nd->root_fh;
|
error = VOP_GETATTR(vp, &attr, procp->p_cred->pc_ucred, procp);
|
||||||
mp = nfs_mountdiskless(nd->root_hostnam, "/", MNT_RDONLY,
|
if (error) panic("nfs_mountroot: getattr for swap");
|
||||||
&nd->root_saddr, &nd->root_args, &vp);
|
n = (long) (attr.va_size / DEV_BSIZE);
|
||||||
|
printf(" swap size: 0x%x (blocks)\n", n); /* XXX */
|
||||||
|
swdevt[0].sw_nblks = n;
|
||||||
|
|
||||||
if (vfs_lock(mp))
|
|
||||||
panic("nfs_mountroot: vfs_lock");
|
|
||||||
TAILQ_INSERT_TAIL(&mountlist, mp, mnt_list);
|
|
||||||
mp->mnt_flag |= MNT_ROOTFS;
|
|
||||||
mp->mnt_vnodecovered = NULLVP;
|
|
||||||
vfs_unlock(mp);
|
|
||||||
rootvp = vp;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
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));
|
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,60 +265,47 @@ nfs_mountroot()
|
||||||
* Internal version of mount system call for diskless setup.
|
* Internal version of mount system call for diskless setup.
|
||||||
*/
|
*/
|
||||||
static struct mount *
|
static struct mount *
|
||||||
nfs_mountdiskless(path, which, mountflag, sin, args, vpp)
|
nfs_mount_diskless(ndmntp, mntname, mntflag, vpp)
|
||||||
char *path;
|
struct nfs_dlmount *ndmntp;
|
||||||
char *which;
|
char *mntname;
|
||||||
int mountflag;
|
int mntflag;
|
||||||
struct sockaddr_in *sin;
|
struct vnode **vpp;
|
||||||
struct nfs_args *args;
|
|
||||||
register struct vnode **vpp;
|
|
||||||
{
|
{
|
||||||
register struct mount *mp;
|
struct nfs_args args;
|
||||||
register struct mbuf *m;
|
struct mount *mp;
|
||||||
register int error;
|
struct mbuf *m;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Create the mount point. */
|
||||||
mp = (struct mount *)malloc((u_long)sizeof(struct mount),
|
mp = (struct mount *)malloc((u_long)sizeof(struct mount),
|
||||||
M_MOUNT, M_NOWAIT);
|
M_MOUNT, M_NOWAIT);
|
||||||
if (mp == NULL)
|
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));
|
bzero((char *)mp, (u_long)sizeof(struct mount));
|
||||||
mp->mnt_op = &nfs_vfsops;
|
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);
|
MGET(m, MT_SONAME, M_DONTWAIT);
|
||||||
if (m == NULL)
|
if (m == NULL)
|
||||||
panic("nfs_mountroot: %s mount mbuf", which);
|
panic("nfs_mountroot: mget soname for %s", mntname);
|
||||||
bcopy((caddr_t)sin, mtod(m, caddr_t), sin->sin_len);
|
bcopy((caddr_t)args.addr, mtod(m, caddr_t),
|
||||||
m->m_len = sin->sin_len;
|
(m->m_len = args.addr->sa_len));
|
||||||
nfsargs_ntoh(args);
|
|
||||||
if (error = mountnfs(args, mp, m, which, path, vpp))
|
if (error = mountnfs(&args, mp, m, mntname, args.hostname, vpp))
|
||||||
panic("nfs_mountroot: mount %s on %s: %d", path, which, error);
|
panic("nfs_mountroot: mount %s failed: %d", mntname);
|
||||||
|
|
||||||
return (mp);
|
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
|
void
|
||||||
nfs_decode_args(nmp, argp)
|
nfs_decode_args(nmp, argp)
|
||||||
struct nfsmount *nmp;
|
struct nfsmount *nmp;
|
||||||
|
|
|
@ -34,34 +34,26 @@
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* from: @(#)nfsdiskless.h 8.1 (Berkeley) 6/10/93
|
* 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.
|
* Structure that must be initialized for a diskless nfs client.
|
||||||
* This structure is used by nfs_mountroot() to set up the root and swap
|
* 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
|
* vnodes plus do a partial ifconfig(8) and route(8) so that the critical
|
||||||
* interface can communicate with the server.
|
* net interface can communicate with the server.
|
||||||
* The primary bootstrap is expected to fill in the appropriate fields before
|
* Whether or not the swap area is nfs mounted is determined
|
||||||
* starting vmunix. Whether or not the swap area is nfs mounted is determined
|
|
||||||
* by the value in swdevt[0]. (equal to NODEV --> swap over nfs)
|
* by the value in swdevt[0]. (equal to NODEV --> swap over nfs)
|
||||||
* Currently only works for AF_INET protocols.
|
* Currently only works for AF_INET protocols.
|
||||||
* NB: All fields are stored in net byte order to avoid hassles with
|
* NB: All fields are stored in net byte order to avoid hassles with
|
||||||
* client/server byte ordering differences.
|
* client/server byte ordering differences.
|
||||||
*/
|
*/
|
||||||
struct nfs_diskless {
|
struct nfs_dlmount {
|
||||||
struct ifaliasreq myif; /* Default interface */
|
struct sockaddr_in ndm_saddr; /* Address of file server */
|
||||||
struct sockaddr_in mygateway; /* Default gateway */
|
char ndm_host[MNAMELEN]; /* Host name for mount pt */
|
||||||
struct nfs_args swap_args; /* Mount args for swap file */
|
u_char ndm_fh[NFS_FHSIZE]; /* The file's file handle */
|
||||||
u_char swap_fh[NFS_FHSIZE]; /* Swap file's file handle */
|
};
|
||||||
struct sockaddr_in swap_saddr; /* Address of swap server */
|
struct nfs_diskless {
|
||||||
char swap_hostnam[MNAMELEN]; /* Host name for mount pt */
|
struct nfs_dlmount nd_root; /* Mount info for root */
|
||||||
int swap_nblks; /* Size of server swap file */
|
struct nfs_dlmount nd_swap; /* Mount info for swap */
|
||||||
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 */
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue