restructure the diskless NFS boot code to keep track of the used

interface and the address allocated, to roll everything back if the
mount fails:
-put an interface pointer into "struct nfs_diskless" to have it
 available for cleanup, don't pass it around anymore where the
 "struct nfs_diskless" is already passed
-add a "cleanup" function which shuts the interface down
-in the protocol-specific parts, either return with "everything
 ready" or "completely shut down"
-use common functions for interface initialization and shutdown
-add a function to delete all routes associate to an interface
 (why is this necessary and not done by ~IFF_UP?)
g/c diskless swap stuff
general cleanup
This commit is contained in:
drochner 1999-02-21 15:07:49 +00:00
parent 4e214e9bac
commit 27098b1199
4 changed files with 278 additions and 142 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_boot.c,v 1.49 1998/09/13 13:49:29 christos Exp $ */
/* $NetBSD: nfs_boot.c,v 1.50 1999/02/21 15:07:49 drochner Exp $ */
/*-
* Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@ -117,6 +117,7 @@ nfs_boot_init(nd, procp)
root_device->dv_xname);
return (ENXIO);
}
nd->nd_ifp = ifp;
error = EADDRNOTAVAIL; /* ??? */
#if defined(NFS_BOOT_BOOTP) || defined(NFS_BOOT_DHCP)
@ -126,13 +127,13 @@ nfs_boot_init(nd, procp)
#else
printf("nfs_boot: trying BOOTP\n");
#endif
error = nfs_bootdhcp(ifp, nd, procp);
error = nfs_bootdhcp(nd, procp);
}
#endif
#ifdef NFS_BOOT_BOOTPARAM
if (error && nfs_boot_bootparam) {
printf("nfs_boot: trying RARP (and RPC/bootparam)\n");
error = nfs_bootparam(ifp, nd, procp);
error = nfs_bootparam(nd, procp);
}
#endif
if (error)
@ -150,11 +151,171 @@ nfs_boot_init(nd, procp)
*/
error = nfs_boot_getfh(&nd->nd_root);
if (error)
nfs_boot_cleanup(nd, procp);
return (error);
}
int nfs_boot_setrecvtimo(so)
struct socket *so;
void
nfs_boot_cleanup(nd, procp)
struct nfs_diskless *nd;
struct proc *procp;
{
nfs_boot_deladdress(nd->nd_ifp, procp, nd->nd_myip.s_addr);
nfs_boot_ifupdown(nd->nd_ifp, procp, 0);
nfs_boot_flushrt(nd->nd_ifp);
}
int
nfs_boot_ifupdown(ifp, procp, up)
struct ifnet *ifp;
struct proc *procp;
int up;
{
struct socket *so;
struct ifreq ireq;
int error;
memset(&ireq, 0, sizeof(ireq));
memcpy(ireq.ifr_name, ifp->if_xname, IFNAMSIZ);
/*
* Get a socket to use for various things in here.
* After this, use "goto out" to cleanup and return.
*/
error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
if (error) {
printf("ifupdown: socreate, error=%d\n", error);
return (error);
}
/*
* Bring up the interface. (just set the "up" flag)
* Get the old interface flags and or IFF_UP into them so
* things like media selection flags are not clobbered.
*/
error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)&ireq, procp);
if (error) {
printf("ifupdown: GIFFLAGS, error=%d\n", error);
goto out;
}
if (up)
ireq.ifr_flags |= IFF_UP;
else
ireq.ifr_flags &= ~IFF_UP;
error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp);
if (error) {
printf("ifupdown: SIFFLAGS, error=%d\n", error);
goto out;
}
out:
soclose(so);
return (error);
}
int
nfs_boot_setaddress(ifp, procp, addr, netmask, braddr)
struct ifnet *ifp;
struct proc *procp;
u_int32_t addr, netmask, braddr;
{
struct socket *so;
struct ifaliasreq iareq;
struct sockaddr_in *sin;
int error;
/*
* Get a socket to use for various things in here.
* After this, use "goto out" to cleanup and return.
*/
error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
if (error) {
printf("setaddress: socreate, error=%d\n", error);
return (error);
}
memset(&iareq, 0, sizeof(iareq));
memcpy(iareq.ifra_name, ifp->if_xname, IFNAMSIZ);
/* Set the I/F address */
sin = (struct sockaddr_in *)&iareq.ifra_addr;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = addr;
/* Set the netmask */
if (netmask != INADDR_ANY) {
sin = (struct sockaddr_in *)&iareq.ifra_mask;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = netmask;
} /* else leave subnetmask unspecified (len=0) */
/* Set the broadcast addr. */
if (braddr != INADDR_ANY) {
sin = (struct sockaddr_in *)&iareq.ifra_broadaddr;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = braddr;
} /* else leave broadcast addr unspecified (len=0) */
error = ifioctl(so, SIOCAIFADDR, (caddr_t)&iareq, procp);
if (error) {
printf("setaddress, error=%d\n", error);
goto out;
}
out:
soclose(so);
return (error);
}
int
nfs_boot_deladdress(ifp, procp, addr)
struct ifnet *ifp;
struct proc *procp;
u_int32_t addr;
{
struct socket *so;
struct ifreq ireq;
struct sockaddr_in *sin;
int error;
/*
* Get a socket to use for various things in here.
* After this, use "goto out" to cleanup and return.
*/
error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
if (error) {
printf("deladdress: socreate, error=%d\n", error);
return (error);
}
memset(&ireq, 0, sizeof(ireq));
memcpy(ireq.ifr_name, ifp->if_xname, IFNAMSIZ);
sin = (struct sockaddr_in *)&ireq.ifr_addr;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = addr;
error = ifioctl(so, SIOCDIFADDR, (caddr_t)&ireq, procp);
if (error) {
printf("deladdress, error=%d\n", error);
goto out;
}
out:
soclose(so);
return (error);
}
int
nfs_boot_setrecvtimo(so)
struct socket *so;
{
struct mbuf *m;
struct timeval *tv;
@ -164,11 +325,12 @@ struct socket *so;
m->m_len = sizeof(*tv);
tv->tv_sec = 1;
tv->tv_usec = 0;
return(sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m));
return (sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m));
}
int nfs_boot_enbroadcast(so)
struct socket *so;
int
nfs_boot_enbroadcast(so)
struct socket *so;
{
struct mbuf *m;
int32_t *on;
@ -177,12 +339,13 @@ struct socket *so;
on = mtod(m, int32_t *);
m->m_len = sizeof(*on);
*on = 1;
return(sosetopt(so, SOL_SOCKET, SO_BROADCAST, m));
return (sosetopt(so, SOL_SOCKET, SO_BROADCAST, m));
}
int nfs_boot_sobind_ipport(so, port)
struct socket *so;
u_int16_t port;
int
nfs_boot_sobind_ipport(so, port)
struct socket *so;
u_int16_t port;
{
struct mbuf *m;
struct sockaddr_in *sin;
@ -196,7 +359,7 @@ u_int16_t port;
sin->sin_port = htons(port);
error = sobind(so, m);
m_freem(m);
return(error);
return (error);
}
/*
@ -208,15 +371,15 @@ u_int16_t port;
#define MAX_RESEND_DELAY 5 /* seconds */
#define TOTAL_TIMEOUT 30 /* seconds */
int nfs_boot_sendrecv(so, nam, sndproc, snd, rcvproc, rcv,
from_p, context)
struct socket *so;
struct mbuf *nam;
int (*sndproc) __P((struct mbuf*, void*, int));
struct mbuf *snd;
int (*rcvproc) __P((struct mbuf*, void*));
struct mbuf **rcv, **from_p;
void *context;
int
nfs_boot_sendrecv(so, nam, sndproc, snd, rcvproc, rcv, from_p, context)
struct socket *so;
struct mbuf *nam;
int (*sndproc) __P((struct mbuf*, void*, int));
struct mbuf *snd;
int (*rcvproc) __P((struct mbuf*, void*));
struct mbuf **rcv, **from_p;
void *context;
{
int error, rcvflg, timo, secs, waited;
struct mbuf *m, *from;
@ -234,7 +397,7 @@ void *context;
send_again:
waited += timo;
if (waited >= TOTAL_TIMEOUT)
return(ETIMEDOUT);
return (ETIMEDOUT);
/* Determine new timeout. */
if (timo < MAX_RESEND_DELAY)
@ -307,7 +470,7 @@ send_again:
}
out:
if (from) m_freem(from);
return(error);
return (error);
}
/*
@ -337,13 +500,40 @@ nfs_boot_defrt(gw_ip)
/* add, dest, gw, mask, flags, 0 */
error = rtrequest(RTM_ADD, &dst, &gw, &mask,
(RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
(RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
if (error) {
printf("nfs_boot: add route, error=%d\n", error);
error = 0;
}
}
static int nfs_boot_delroute __P((struct radix_node *, void *));
static int
nfs_boot_delroute(rn, w)
struct radix_node *rn;
void *w;
{
struct rtentry *rt = (struct rtentry *)rn;
int error;
if (rt->rt_ifp != (struct ifnet *)w)
return (0);
error = rtrequest(RTM_DELETE, rt_key(rt), NULL, rt_mask(rt), 0, NULL);
if (error)
printf("nfs_boot: del route, error=%d\n", error);
return (0);
}
void
nfs_boot_flushrt(ifp)
struct ifnet *ifp;
{
rn_walktree(rt_tables[AF_INET], nfs_boot_delroute, ifp);
}
/*
* Get an initial NFS file handle using Sun RPC/mountd.
* Separate function because we used to call it twice.

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_bootdhcp.c,v 1.10 1999/02/12 01:38:38 thorpej Exp $ */
/* $NetBSD: nfs_bootdhcp.c,v 1.11 1999/02/21 15:07:49 drochner Exp $ */
/*-
* Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@ -220,8 +220,7 @@ static const u_int8_t vm_rfc1048[4] = { 99, 130, 83, 99 };
/* Convenience macro */
#define INTOHL(ina) ((u_int32_t)ntohl((ina).s_addr))
static int bootpc_call __P((struct socket *, struct ifnet *,
struct nfs_diskless *, struct proc *));
static int bootpc_call __P((struct nfs_diskless *, struct proc *));
static void bootp_extract __P((struct bootp *, int, struct nfs_diskless *));
/* #define DEBUG XXX */
@ -237,57 +236,30 @@ static void bootp_extract __P((struct bootp *, int, struct nfs_diskless *));
* Get our boot parameters using BOOTP.
*/
int
nfs_bootdhcp(ifp, nd, procp)
struct ifnet *ifp;
nfs_bootdhcp(nd, procp)
struct nfs_diskless *nd;
struct proc *procp;
{
struct ifaliasreq iareq;
struct socket *so;
struct sockaddr_in *sin;
struct ifnet *ifp = nd->nd_ifp;
int error;
/*
* Get a socket to use for various things in here.
* After this, use "goto out" to cleanup and return.
*/
error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
if (error) {
printf("nfs_boot: socreate, error=%d\n", error);
return (error);
}
/*
* Do enough of ifconfig(8) so that the chosen interface
* can talk to the servers. Use address zero for now.
*/
memset(&iareq, 0, sizeof(iareq));
memcpy(iareq.ifra_name, ifp->if_xname, IFNAMSIZ);
/* Set the I/F address */
sin = (struct sockaddr_in *)&iareq.ifra_addr;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = INADDR_ANY;
/* Leave subnetmask unspecified (len=0) */
/* Set the broadcast addr. */
sin = (struct sockaddr_in *)&iareq.ifra_broadaddr;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_addr.s_addr = INADDR_BROADCAST;
error = ifioctl(so, SIOCAIFADDR, (caddr_t)&iareq, procp);
error = nfs_boot_setaddress(ifp, procp, INADDR_ANY, INADDR_ANY,
INADDR_BROADCAST);
if (error) {
printf("nfs_boot: set ifaddr zero, error=%d\n", error);
goto out;
return (error);
}
/* This function call does the real send/recv work. */
error = bootpc_call(so, ifp, nd, procp);
error = bootpc_call(nd, procp);
/* Get rid of the temporary (zero) IP address. */
/*
* XXX SIOCDIFADDR takes a "struct ifreq", which is
* an exact subset of "struct ifaliasreq".
*/
(void) ifioctl(so, SIOCDIFADDR, (caddr_t)&iareq, procp);
(void) nfs_boot_deladdress(ifp, procp, INADDR_ANY);
/* NOW we can test the error from bootpc_call. */
if (error)
goto out;
@ -295,29 +267,18 @@ nfs_bootdhcp(ifp, nd, procp)
/*
* Do ifconfig with our real IP address and mask.
*/
/* I/F address */
sin = (struct sockaddr_in *)&iareq.ifra_addr;
sin->sin_addr = nd->nd_myip;
/* subnetmask */
if (nd->nd_mask.s_addr) {
sin = (struct sockaddr_in *)&iareq.ifra_mask;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_addr = nd->nd_mask;
}
/* Let ifioctl() default the broadcast address. */
sin = (struct sockaddr_in *)&iareq.ifra_broadaddr;
sin->sin_len = 0;
sin->sin_family = 0;
sin->sin_addr.s_addr = 0;
error = ifioctl(so, SIOCAIFADDR, (caddr_t)&iareq, procp);
error = nfs_boot_setaddress(ifp, procp, nd->nd_myip.s_addr,
nd->nd_mask.s_addr, INADDR_ANY);
if (error) {
printf("nfs_boot: set ifaddr real, error=%d\n", error);
goto out;
}
out:
soclose(so);
if (error) {
(void) nfs_boot_ifupdown(ifp, procp, 0);
nfs_boot_flushrt(ifp);
}
return (error);
}
@ -470,12 +431,12 @@ warn:
}
static int
bootpc_call(so, ifp, nd, procp)
struct socket *so;
struct ifnet *ifp;
bootpc_call(nd, procp)
struct nfs_diskless *nd;
struct proc *procp;
{
struct socket *so;
struct ifnet *ifp = nd->nd_ifp;
static u_int32_t xid = ~0xFF;
struct bootp *bootp; /* request */
struct mbuf *m, *nam;
@ -485,6 +446,12 @@ bootpc_call(so, ifp, nd, procp)
u_char hafmt, halen;
struct bootpcontext bpc;
error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
if (error) {
printf("bootp: socreate, error=%d\n", error);
return (error);
}
/*
* Initialize to NULL anything that will hold an allocation,
* and free each at the end if not null.
@ -650,6 +617,7 @@ out:
m_freem(m);
if (nam)
m_freem(nam);
soclose(so);
return (error);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfs_bootparam.c,v 1.10 1998/09/13 13:49:29 christos Exp $ */
/* $NetBSD: nfs_bootparam.c,v 1.11 1999/02/21 15:07:49 drochner Exp $ */
/*-
* Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@ -107,52 +107,28 @@ static int bp_getfile __P((struct sockaddr_in *bpsin, char *key,
* is used for all subsequent booptaram RPCs.
*/
int
nfs_bootparam(ifp, nd, procp)
struct ifnet *ifp;
nfs_bootparam(nd, procp)
struct nfs_diskless *nd;
struct proc *procp;
{
struct ifreq ireq;
struct in_addr my_ip, gw_ip;
struct ifnet *ifp = nd->nd_ifp;
struct in_addr my_ip, arps_ip, gw_ip;
struct sockaddr_in bp_sin;
struct sockaddr_in *sin;
struct socket *so;
struct nfs_dlmount *gw_ndm;
#if 0 /* XXX - not yet */
struct nfs_dlmount *gw_ndm = 0;
char *p;
u_int32_t mask;
#endif /* XXX */
int error;
gw_ndm = 0;
memset(&ireq, 0, sizeof(ireq));
memcpy(ireq.ifr_name, ifp->if_xname, IFNAMSIZ);
/*
* Get a socket to use for various things in here.
* After this, use "goto out" to cleanup and return.
*/
error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
if (error) {
printf("nfs_boot: socreate, error=%d\n", error);
return (error);
}
/*
* Bring up the interface. (just set the "up" flag)
* Get the old interface flags and or IFF_UP into them so
* things like media selection flags are not clobbered.
*/
error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)&ireq, procp);
if (error) {
printf("nfs_boot: GIFFLAGS, error=%d\n", error);
goto out;
}
ireq.ifr_flags |= IFF_UP;
error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp);
error = nfs_boot_ifupdown(ifp, procp, 1);
if (error) {
printf("nfs_boot: SIFFLAGS, error=%d\n", error);
goto out;
return (error);
}
error = EADDRNOTAVAIL; /* ??? */
@ -161,7 +137,7 @@ nfs_bootparam(ifp, nd, procp)
/*
* Do RARP for the interface address.
*/
error = revarpwhoami(&my_ip, ifp);
error = revarpwhoarewe(ifp, &arps_ip, &my_ip);
if (error) {
printf("revarp failed, error=%d\n", error);
goto out;
@ -170,18 +146,16 @@ nfs_bootparam(ifp, nd, procp)
#endif
nd->nd_myip.s_addr = my_ip.s_addr;
printf("nfs_boot: client_addr=0x%x\n",
(u_int32_t)ntohl(my_ip.s_addr));
printf("nfs_boot: client_addr=0x%x (RARP from 0x%x)\n",
(u_int32_t)ntohl(my_ip.s_addr),
(u_int32_t)ntohl(arps_ip.s_addr));
/*
* Do enough of ifconfig(8) so that the chosen interface
* can talk to the servers. (just set the address)
*/
sin = (struct sockaddr_in *)&ireq.ifr_addr;
sin->sin_len = sizeof(*sin);
sin->sin_family = AF_INET;
sin->sin_addr = my_ip;
error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp);
error = nfs_boot_setaddress(ifp, procp, my_ip.s_addr,
INADDR_ANY, INADDR_ANY);
if (error) {
printf("nfs_boot: set ifaddr, error=%d\n", error);
goto out;
@ -205,7 +179,7 @@ nfs_bootparam(ifp, nd, procp)
error = bp_whoami(sin, &my_ip, &gw_ip);
if (error) {
printf("nfs_boot: bootparam whoami, error=%d\n", error);
goto out;
goto delout;
}
printf("nfs_boot: server_addr=0x%x\n",
(u_int32_t)ntohl(sin->sin_addr.s_addr));
@ -218,15 +192,8 @@ nfs_bootparam(ifp, nd, procp)
error = bp_getfile(sin, "root", &nd->nd_root);
if (error) {
printf("nfs_boot: bootparam get root: %d\n", error);
goto out;
goto delout;
}
#if 0
error = bp_getfile(sin, "swap", &nd->nd_swap);
if (error) {
printf("nfs_boot: bootparam get swap: %d\n", error);
error = 0;
}
#endif
#ifdef NFS_BOOT_GATEWAY
/*
@ -281,12 +248,18 @@ nfs_bootparam(ifp, nd, procp)
printf("nfs_boot: set ifmask, error=%d\n", error);
error = 0; /* ignore it */
}
#endif /* XXX */
out:
if (gw_ndm)
free(gw_ndm, M_NFSMNT);
soclose(so);
#endif /* XXX */
delout:
if (error)
(void) nfs_boot_deladdress(ifp, procp, my_ip.s_addr);
out:
if (error) {
(void) nfs_boot_ifupdown(ifp, procp, 0);
nfs_boot_flushrt(ifp);
}
return (error);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: nfsdiskless.h,v 1.15 1997/09/30 20:44:35 drochner Exp $ */
/* $NetBSD: nfsdiskless.h,v 1.16 1999/02/21 15:07:49 drochner Exp $ */
/*-
* Copyright (c) 1995, 1997 The NetBSD Foundation, Inc.
@ -55,18 +55,23 @@ struct nfs_dlmount {
u_char ndm_fh[NFSX_V3FHMAX]; /* The file's file handle */
};
struct nfs_diskless {
/* the interface used */
struct ifnet *nd_ifp;
/* A collection of IP addresses, for convenience. */
struct in_addr nd_myip; /* My IP address */
struct in_addr nd_mask; /* My netmask */
struct in_addr nd_gwip; /* My gateway */
/* Information for each mount point we need. */
struct nfs_dlmount nd_root; /* Mount info for root */
#if 0
struct nfs_dlmount nd_swap; /* Mount info for swap */
#endif
};
int nfs_boot_init __P((struct nfs_diskless *nd, struct proc *procp));
void nfs_boot_cleanup __P((struct nfs_diskless *nd, struct proc *procp));
int nfs_boot_ifupdown __P((struct ifnet *, struct proc *, int));
int nfs_boot_setaddress __P((struct ifnet *, struct proc *,
u_int32_t, u_int32_t, u_int32_t));
int nfs_boot_deladdress __P((struct ifnet *, struct proc *, u_int32_t));
void nfs_boot_flushrt __P((struct ifnet *));
int nfs_boot_setrecvtimo __P((struct socket *));
int nfs_boot_enbroadcast __P((struct socket *));
int nfs_boot_sobind_ipport __P((struct socket *, u_int16_t));
@ -75,6 +80,6 @@ int nfs_boot_sendrecv __P((struct socket *, struct mbuf *,
int (*)(struct mbuf*, void*), struct mbuf**,
struct mbuf**, void*));
int nfs_bootdhcp __P((struct ifnet *, struct nfs_diskless *, struct proc *));
int nfs_bootparam __P((struct ifnet *, struct nfs_diskless *, struct proc *));
int nfs_bootdhcp __P((struct nfs_diskless *, struct proc *));
int nfs_bootparam __P((struct nfs_diskless *, struct proc *));