Page MenuHomeFreeBSD

D22487.diff
No OneTemporary

D22487.diff

Index: sys/fs/nfsclient/nfs_clvfsops.c
===================================================================
--- sys/fs/nfsclient/nfs_clvfsops.c
+++ sys/fs/nfsclient/nfs_clvfsops.c
@@ -40,6 +40,8 @@
#include "opt_bootp.h"
#include "opt_nfsroot.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -161,8 +163,8 @@
* isn't used in that case.
*/
#if !defined(NFS_ROOT)
-struct nfs_diskless nfs_diskless = { { { 0 } } };
-struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
+struct nfs_diskless nfs_diskless = { AF_UNSPEC, NULL, { { 0 } } };
+struct nfsv3_diskless nfsv3_diskless = { AF_UNSPEC, NULL, { { 0 } } };
int nfs_diskless_valid = 0;
#endif
@@ -173,14 +175,14 @@
SYSCTL_STRING(_vfs_nfs, OID_AUTO, diskless_rootpath, CTLFLAG_RD,
nfsv3_diskless.root_hostnam, 0, "Path to nfs root");
+/* XXX-BZ unused and not correct anymore. */
SYSCTL_OPAQUE(_vfs_nfs, OID_AUTO, diskless_rootaddr, CTLFLAG_RD,
&nfsv3_diskless.root_saddr, sizeof(nfsv3_diskless.root_saddr),
"%Ssockaddr_in", "Diskless root nfs address");
void newnfsargs_ntoh(struct nfs_args *);
-static int nfs_mountdiskless(char *,
- struct sockaddr_in *, struct nfs_args *,
+static int nfs_mountdiskless(struct nfsv3_diskless *nd,
struct thread *, struct vnode **, struct mount *);
static void nfs_convert_diskless(void);
static void nfs_convert_oargs(struct nfs_args *args,
@@ -254,10 +256,33 @@
nfs_convert_diskless(void)
{
- bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
- sizeof(struct ifaliasreq));
- bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
- sizeof(struct sockaddr_in));
+ switch (nfs_diskless.sa_family) {
+#ifdef INET
+ case PF_INET:
+ bcopy(&nfs_diskless.myif, &nfsv3_diskless.myif,
+ sizeof(struct ifaliasreq));
+ bcopy(&nfs_diskless.mygateway, &nfsv3_diskless.mygateway,
+ sizeof(struct sockaddr_in));
+ bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
+ sizeof(struct sockaddr_in));
+ break;
+#endif
+#ifdef INET6
+ case PF_INET6:
+ bcopy(&nfs_diskless.myif6, &nfsv3_diskless.myif6,
+ sizeof(nfs_diskless.myif6));
+ bcopy(&nfs_diskless.mygateway6, &nfsv3_diskless.mygateway6,
+ sizeof(nfs_diskless.mygateway6));
+ bcopy(&nfs_diskless.root_saddr6,&nfsv3_diskless.root_saddr6,
+ sizeof(nfs_diskless.root_saddr6));
+ break;
+#endif
+ default:
+ panic("%s: are you trying to trick me? sa_family %u\n",
+ __func__, nfs_diskless._mygateway.sa.sa_family);
+ }
+ nfsv3_diskless.sa_family = nfs_diskless.sa_family;
+ nfsv3_diskless.ifp = nfs_diskless.ifp;
nfs_convert_oargs(&nfsv3_diskless.root_args,&nfs_diskless.root_args);
if (nfsv3_diskless.root_args.flags & NFSMNT_NFSV3) {
nfsv3_diskless.root_fhsize = NFSX_MYFH;
@@ -266,8 +291,6 @@
nfsv3_diskless.root_fhsize = NFSX_V2FH;
bcopy(nfs_diskless.root_fh, nfsv3_diskless.root_fh, NFSX_V2FH);
}
- bcopy(&nfs_diskless.root_saddr,&nfsv3_diskless.root_saddr,
- sizeof(struct sockaddr_in));
bcopy(nfs_diskless.root_hostnam, nfsv3_diskless.root_hostnam, MNAMELEN);
nfsv3_diskless.root_time = nfs_diskless.root_time;
bcopy(nfs_diskless.my_hostnam, nfsv3_diskless.my_hostnam,
@@ -403,9 +426,7 @@
struct vnode *vp;
struct ifreq ir;
int error;
- u_long l;
- char buf[128];
- char *cp;
+ char *afstr, *cp;
#if defined(BOOTP_NFSROOT) && defined(BOOTP)
bootpc_init(); /* use bootp to get nfs_diskless filled in */
@@ -422,38 +443,37 @@
* Do enough of ifconfig(8) so that the critical net interface can
* talk to the server.
*/
- error = socreate(nd->myif.ifra_addr.sa_family, &so, nd->root_args.sotype, 0,
+ error = socreate(nd->sa_family, &so, nd->root_args.sotype, 0,
td->td_ucred, td);
if (error)
- panic("nfs_mountroot: socreate(%04x): %d",
- nd->myif.ifra_addr.sa_family, error);
+ panic("%s: socreate(%04x): %d", __func__, nd->sa_family, error);
-#if 0 /* XXX Bad idea */
- /*
- * We might not have been told the right interface, so we pass
- * over the first ten interfaces of the same kind, until we get
- * one of them configured.
- */
-
- for (i = strlen(nd->myif.ifra_name) - 1;
- nd->myif.ifra_name[i] >= '0' &&
- nd->myif.ifra_name[i] <= '9';
- nd->myif.ifra_name[i] ++) {
+ afstr = "";
+ switch (nd->sa_family) {
+#ifdef INET
+ case PF_INET:
error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
- if(!error)
- break;
- }
+ break;
#endif
- error = ifioctl(so, SIOCAIFADDR, (caddr_t)&nd->myif, td);
+#ifdef INET6
+ case PF_INET6:
+ error = ifioctl(so, SIOCAIFADDR_IN6, (caddr_t)&nd->myif6, td);
+ afstr = "_IN6";
+ break;
+#endif
+ default:
+ error = EPFNOSUPPORT;
+ break;
+ }
if (error)
- panic("nfs_mountroot: SIOCAIFADDR: %d", error);
+ panic("%s: SIOCAIFADDR%s: %d", __func__, afstr, error);
if ((cp = kern_getenv("boot.netif.mtu")) != NULL) {
ir.ifr_mtu = strtol(cp, NULL, 10);
bcopy(nd->myif.ifra_name, ir.ifr_name, IFNAMSIZ);
freeenv(cp);
error = ifioctl(so, SIOCSIFMTU, (caddr_t)&ir, td);
if (error)
- printf("nfs_mountroot: SIOCSIFMTU: %d", error);
+ printf("%s: SIOCSIFMTU: %d", __func__, error);
}
soclose(so);
@@ -463,7 +483,8 @@
* is not set by the DHCP server. Check also for a value of 0
* to avoid panicking inappropriately in that situation.
*/
- if (nd->mygateway.sin_len != 0 &&
+#ifdef INET
+ if (nd->sa_family == PF_INET && nd->mygateway.sin_len != 0 &&
nd->mygateway.sin_addr.s_addr != 0) {
struct sockaddr_in mask, sin;
@@ -479,22 +500,37 @@
RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
CURVNET_RESTORE();
if (error)
- panic("nfs_mountroot: RTM_ADD: %d", error);
+ panic("%s: RTM_ADD: %d", __func__, error);
}
+#endif
+#ifdef INET6
+ if (nd->sa_family == PF_INET6 && nd->mygateway6.sin6_len != 0 &&
+ !IN6_IS_ADDR_UNSPECIFIED(&nd->mygateway6.sin6_addr)) {
+ struct sockaddr_in6 sin6, mask;
+ bzero(&sin6, sizeof(sin6));
+ bzero(&mask, sizeof(mask));
+ sin6.sin6_family = PF_INET6;
+ sin6.sin6_len = mask.sin6_len = sizeof(mask);
+ /* XXX MRT use table 0 for this sort of thing */
+ CURVNET_SET(TD_TO_VNET(td));
+ error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&sin6,
+ (struct sockaddr *)&nd->mygateway6,
+ (struct sockaddr *)&mask,
+ RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
+ CURVNET_RESTORE();
+ if (error)
+ panic("%s: RTM_ADD: %d", __func__, error);
+
+ }
+#endif
+
/*
* Create the rootfs mount point.
*/
nd->root_args.fh = nd->root_fh;
nd->root_args.fhsize = nd->root_fhsize;
- l = ntohl(nd->root_saddr.sin_addr.s_addr);
- snprintf(buf, sizeof(buf), "%ld.%ld.%ld.%ld:%s",
- (l >> 24) & 0xff, (l >> 16) & 0xff,
- (l >> 8) & 0xff, (l >> 0) & 0xff, nd->root_hostnam);
- printf("NFS ROOT: %s\n", buf);
- nd->root_args.hostname = buf;
- if ((error = nfs_mountdiskless(buf,
- &nd->root_saddr, &nd->root_args, td, &vp, mp)) != 0) {
+ if ((error = nfs_mountdiskless(nd, td, &vp, mp)) != 0) {
return (error);
}
@@ -515,28 +551,77 @@
* Internal version of mount system call for diskless setup.
*/
static int
-nfs_mountdiskless(char *path,
- struct sockaddr_in *sin, struct nfs_args *args, struct thread *td,
- struct vnode **vpp, struct mount *mp)
+nfs_mountdiskless(struct nfsv3_diskless *nd,
+ struct thread *td, struct vnode **vpp, struct mount *mp)
{
+#ifdef INET6
+ char sname6[INET6_ADDRSTRLEN];
+ struct sockaddr_in6 *sin6;
+#endif
+#ifdef INET
+ char sname[INET_ADDRSTRLEN];
+ struct sockaddr_in *sin;
+#endif
struct sockaddr *nam;
int dirlen, error;
+ char buf[128];
char *dirpath;
+ switch (nd->sa_family) {
+#ifdef INET
+ case PF_INET:
+ sin = &nd->root_saddr;
+ inet_ntop(PF_INET, &sin->sin_addr, sname, sizeof(sname));
+ snprintf(buf, sizeof(buf), "%s:%s", sname, nd->root_hostnam);
+ nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
+ break;
+#endif
+#ifdef INET6
+ case PF_INET6:
+ sin6 = &nd->root_saddr6;
+ inet_ntop(PF_INET6, &sin6->sin6_addr, sname6, sizeof(sname6));
+ snprintf(buf, sizeof(buf), "[%s]:%s", sname6, nd->root_hostnam);
+ nam = sodupsockaddr((struct sockaddr *)sin6, M_WAITOK);
+ break;
+#endif
+ default:
+ printf(buf, sizeof(buf),
+ "%s: IP support in your config is:/nonexistent", __func__);
+ return (EPFNOSUPPORT);
+ }
+
+ printf("NFS ROOT: %s\n", buf);
+ nd->root_args.hostname = buf;
+
/*
* Find the directory path in "path", which also has the server's
* name/ip address in it.
*/
- dirpath = strchr(path, ':');
+ dirpath = nd->root_hostnam;
if (dirpath != NULL)
- dirlen = strlen(++dirpath);
+ dirlen = strlen(dirpath);
else
dirlen = 0;
- nam = sodupsockaddr((struct sockaddr *)sin, M_WAITOK);
- if ((error = mountnfs(args, mp, nam, path, NULL, 0, dirpath, dirlen,
- NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
+
+ if (nd->ifp != NULL && nd->ifp->if_link_state != LINK_STATE_UP) {
+ if (bootverbose)
+ printf("%s: waiting for link up..\n", __func__);
+ for (error = 0; nd->ifp != NULL && error < 10; error++) {
+ if (nd->ifp->if_link_state == LINK_STATE_UP) {
+ break;
+ }
+ pause("nfslink", hz);
+ }
+ if (bootverbose)
+ printf("%s: link %s\n", __func__,
+ (nd->ifp->if_link_state == LINK_STATE_UP) ?
+ "UP" : "DOWN");
+ }
+
+ if ((error = mountnfs(&nd->root_args, mp, nam, buf, NULL, 0, dirpath,
+ dirlen, NULL, 0, vpp, td->td_ucred, td, NFS_DEFAULT_NAMETIMEO,
NFS_DEFAULT_NEGNAMETIMEO, 0)) != 0) {
- printf("nfs_mountroot: mount %s on /: %d\n", path, error);
+ printf("%s: mount %s on /: %d\n", __func__, buf, error);
return (error);
}
return (0);
@@ -829,7 +914,7 @@
/*
* XXX: hardcoded port number.
*/
- sin->sin_port = htons(2049);
+ sin->sin_port = htons(NFS_PORT);
*hostnamep = strdup(nam, M_NEWNFSMNT);
*sinp = sin;
Index: sys/nfs/nfs_diskless.c
===================================================================
--- sys/nfs/nfs_diskless.c
+++ sys/nfs/nfs_diskless.c
@@ -38,6 +38,8 @@
__FBSDID("$FreeBSD$");
#include "opt_bootp.h"
+#include "opt_inet.h"
+#include "opt_inet6.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -54,14 +56,27 @@
#include <net/ethernet.h>
#include <net/vnet.h>
+#if defined(INET6) || defined(INET)
#include <netinet/in.h>
+#endif
+#if defined(INET6)
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+#endif
+
#include <nfs/nfsproto.h>
#include <nfsclient/nfs.h>
#include <nfs/nfsdiskless.h>
#define NFS_IFACE_TIMEOUT_SECS 10 /* Timeout for interface to appear. */
+#ifdef INET
static int inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa);
+#endif
+#ifdef INET6
+static int in6addr_to_sockaddr(char *ev, struct sockaddr_in6 *sin6,
+ struct sockaddr_in6 *in6mask);
+#endif
static int hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa);
static int decode_nfshandle(char *ev, u_char *fh, int maxfh);
@@ -70,8 +85,8 @@
* 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 } } };
-struct nfsv3_diskless nfsv3_diskless = { { { 0 } } };
+struct nfs_diskless nfs_diskless = { AF_UNSPEC, NULL, { { 0 } } };
+struct nfsv3_diskless nfsv3_diskless = { AF_UNSPEC, NULL, { { 0 } } };
int nfs_diskless_valid = 0;
/*
@@ -146,18 +161,52 @@
free(opts, M_TEMP);
}
+#ifdef INET6
+static void
+setup_myif6(struct in6_aliasreq *ifr,
+ struct sockaddr_in6 *sin6, struct sockaddr_in6 *mask)
+{
+
+ bcopy(sin6, &ifr->ifra_addr, sizeof(*sin6));
+ /* ifra_dstaddr */
+ bcopy(mask, &ifr->ifra_prefixmask, sizeof(*mask));
+ ifr->ifra_flags = 0;
+ ifr->ifra_lifetime.ia6t_expire = 0;
+ ifr->ifra_lifetime.ia6t_preferred = 0;
+ ifr->ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+ ifr->ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
+}
+#endif
+
+#ifdef INET
+static void
+setup_myif(struct ifaliasreq *ifr,
+ struct sockaddr_in *sin, struct sockaddr_in *netmask)
+{
+
+ bcopy(sin, &ifr->ifra_addr, sizeof(*sin));
+ bcopy(sin, &ifr->ifra_broadaddr, sizeof(*sin));
+ ((struct sockaddr_in *)&ifr->ifra_broadaddr)->sin_addr.s_addr =
+ sin->sin_addr.s_addr | ~ netmask->sin_addr.s_addr;
+ bcopy(netmask, &ifr->ifra_mask, sizeof(*netmask));
+}
+#endif
+
/*
* Populate the essential fields in the nfsv3_diskless structure.
*
* The loader is expected to export the following environment variables:
*
* boot.netif.name name of boot interface
- * boot.netif.ip IP address on boot interface
- * boot.netif.netmask netmask on boot interface
- * boot.netif.gateway default gateway (optional)
+ * boot.netif.ip IPv4 address on boot interface
+ * boot.netif.netmask IPv4 netmask on boot interface
+ * boot.netif.gateway IPv4 default gateway (optional)
+ * boot.netif.ip6 IPv6 address on boot interface
+ * boot.netif.gateway6 IPv6 default gateway (optional)
* boot.netif.hwaddr hardware address of boot interface
* boot.netif.mtu interface mtu from bootp/dhcp (optional)
- * boot.nfsroot.server IP address of root filesystem server
+ * boot.nfsroot.server IPv4 address of root filesystem server
+ * boot.nfsroot.server6 IPv6 address of root filesystem server
* boot.nfsroot.path path of the root filesystem on server
* boot.nfsroot.nfshandle NFS handle for root filesystem on server
* boot.nfsroot.nfshandlelen and length of this handle (for NFSv3 only)
@@ -171,7 +220,14 @@
struct ifnet *ifp;
struct ifaddr *ifa;
struct sockaddr_dl *sdl, ourdl;
- struct sockaddr_in myaddr, netmask;
+#ifdef INET
+ struct sockaddr_in sin, netmask;
+ bool ipv4;
+#endif
+#ifdef INET6
+ struct sockaddr_in6 sin6, in6mask;
+ bool ipv6;
+#endif
char *cp;
int cnt, fhlen, is_nfsv3;
uint32_t len;
@@ -180,43 +236,88 @@
if (nfs_diskless_valid != 0)
return;
+#if !defined(INET6) && !defined(INET)
+ printf("%s failing: neither INET nor INET6 support.\n", __func__);
+ return;
+#endif
+
/* get handle size. If this succeeds, it's an NFSv3 setup. */
if ((cp = kern_getenv("boot.nfsroot.nfshandlelen")) != NULL) {
cnt = sscanf(cp, "%d", &len);
freeenv(cp);
if (cnt != 1 || len == 0 || len > NFSX_V3FHMAX) {
- printf("nfs_diskless: bad NFS handle len\n");
+ printf("%s: bad NFS handle len\n", __func__);
return;
}
nd3->root_fhsize = len;
is_nfsv3 = 1;
} else
is_nfsv3 = 0;
- /* set up interface */
- if (inaddr_to_sockaddr("boot.netif.ip", &myaddr))
- return;
- if (inaddr_to_sockaddr("boot.netif.netmask", &netmask)) {
- printf("nfs_diskless: no netmask\n");
- return;
+ /*
+ * Set up interface.
+ * For now assume that v4 and v6 addresses are stored
+ * in different env. variables from loader. Prefer v6 if
+ * available. Trying a fallback to a 2nd choice is hard in this
+ * NFS code. If you want v4 do not set v6.
+ */
+#ifdef INET6
+ ipv6 = true;
+ if (ipv6 && in6addr_to_sockaddr("boot.netif.ip6", &sin6, &in6mask)) {
+ if (bootverbose)
+ printf("%s: skipping IPv6, no prefix.\n", __func__);
+ ipv6 = false;
}
+#endif
+#ifdef INET
+ ipv4 = true;
+ if (ipv4 && inaddr_to_sockaddr("boot.netif.ip", &sin)) {
+ if (bootverbose)
+ printf("%s: skipping IPv4, no address.\n", __func__);
+ ipv4 = false;
+ }
+ if (ipv4 && inaddr_to_sockaddr("boot.netif.netmask", &netmask)) {
+ if (bootverbose)
+ printf("%s: skipping IPv4, no netmask.\n", __func__);
+ ipv4 = false;
+ }
+#endif
+
if (is_nfsv3 != 0) {
- bcopy(&myaddr, &nd3->myif.ifra_addr, sizeof(myaddr));
- bcopy(&myaddr, &nd3->myif.ifra_broadaddr, sizeof(myaddr));
- ((struct sockaddr_in *)
- &nd3->myif.ifra_broadaddr)->sin_addr.s_addr =
- myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
- bcopy(&netmask, &nd3->myif.ifra_mask, sizeof(netmask));
+#ifdef INET6
+ if (ipv6) {
+ nd3->sa_family = AF_INET6;
+ setup_myif6(&nd3->myif6, &sin6, &in6mask);
+ }
+#endif
+#if defined(INET6) && defined(INET)
+ else
+#endif
+#ifdef INET
+ if (ipv4) {
+ nd3->sa_family = AF_INET;
+ setup_myif(&nd3->myif, &sin, &netmask);
+ }
+#endif
} else {
- bcopy(&myaddr, &nd->myif.ifra_addr, sizeof(myaddr));
- bcopy(&myaddr, &nd->myif.ifra_broadaddr, sizeof(myaddr));
- ((struct sockaddr_in *)
- &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
- myaddr.sin_addr.s_addr | ~ netmask.sin_addr.s_addr;
- bcopy(&netmask, &nd->myif.ifra_mask, sizeof(netmask));
+#ifdef INET6
+ if (ipv6) {
+ nd->sa_family = AF_INET6;
+ setup_myif6(&nd->myif6, &sin6, &in6mask);
+ }
+#endif
+#if defined(INET6) && defined(INET)
+ else
+#endif
+#ifdef INET
+ if (ipv4) {
+ nd->sa_family = AF_INET;
+ setup_myif(&nd->myif, &sin, &netmask);
+ }
+#endif
}
if (hwaddr_to_sockaddr("boot.netif.hwaddr", &ourdl)) {
- printf("nfs_diskless: no hardware address\n");
+ printf("%s aborting: no hardware address\n", __func__);
return;
}
ifa = NULL;
@@ -246,37 +347,58 @@
pause("nfssdl", hz / 5);
goto retry;
}
- printf("nfs_diskless: no interface\n");
+ printf("%s: no interface\n", __func__);
return; /* no matching interface */
match_done:
kern_setenv("boot.netif.name", ifp->if_xname);
- if (is_nfsv3 != 0) {
- strlcpy(nd3->myif.ifra_name, ifp->if_xname,
- sizeof(nd3->myif.ifra_name));
-
- /* set up gateway */
- inaddr_to_sockaddr("boot.netif.gateway", &nd3->mygateway);
+ if (is_nfsv3 != 0) {
+ nd3->ifp = ifp; /* XXX-BZ this is a dangerous game; ref it! */
+#ifdef INET6
+ if (ipv6) {
+ strlcpy(nd3->myif6.ifra_name, ifp->if_xname,
+ sizeof(nd3->myif6.ifra_name));
+ if (in6addr_to_sockaddr("boot.nfsroot.server6",
+ &nd3->root_saddr6, NULL)) {
+ printf("%s: no IPv6 server\n", __func__);
+ return;
+ }
+ nd3->root_saddr6.sin6_port = htons(NFS_PORT);
+ in6addr_to_sockaddr("boot.netif.gateway6",
+ &nd3->mygateway6, NULL);
+ }
+#endif
+#if defined(INET6) && defined(INET)
+ else
+#endif
+#ifdef INET
+ if (ipv4) {
+ strlcpy(nd3->myif.ifra_name, ifp->if_xname,
+ sizeof(nd3->myif.ifra_name));
+ if (inaddr_to_sockaddr("boot.nfsroot.server",
+ &nd3->root_saddr)) {
+ printf("%s: no IPv4 server\n", __func__);
+ return;
+ }
+ nd3->root_saddr.sin_port = htons(NFS_PORT);
+ inaddr_to_sockaddr("boot.netif.gateway",
+ &nd3->mygateway);
+ }
+#endif
/* set up root mount */
nd3->root_args.rsize = 32768; /* XXX tunable? */
nd3->root_args.wsize = 32768;
nd3->root_args.sotype = SOCK_STREAM;
nd3->root_args.flags = (NFSMNT_NFSV3 | NFSMNT_WSIZE |
NFSMNT_RSIZE | NFSMNT_RESVPORT);
- if (inaddr_to_sockaddr("boot.nfsroot.server",
- &nd3->root_saddr)) {
- printf("nfs_diskless: no server\n");
- return;
- }
- nd3->root_saddr.sin_port = htons(NFS_PORT);
fhlen = decode_nfshandle("boot.nfsroot.nfshandle",
&nd3->root_fh[0], NFSX_V3FHMAX);
if (fhlen == 0) {
- printf("nfs_diskless: no NFS handle\n");
+ printf("%s: no NFS handle\n", __func__);
return;
}
if (fhlen != nd3->root_fhsize) {
- printf("nfs_diskless: bad NFS handle len=%d\n", fhlen);
+ printf("%s: bad NFS handle len=%d\n", __func__, fhlen);
return;
}
if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) {
@@ -290,27 +412,48 @@
nfs_diskless_valid = 3;
} else {
- strlcpy(nd->myif.ifra_name, ifp->if_xname,
- sizeof(nd->myif.ifra_name));
-
- /* set up gateway */
- inaddr_to_sockaddr("boot.netif.gateway", &nd->mygateway);
-
+ nd->ifp = ifp;
+#ifdef INET6
+ if (ipv6) {
+ strlcpy(nd->myif6.ifra_name, ifp->if_xname,
+ sizeof(nd->myif6.ifra_name));
+ if (in6addr_to_sockaddr("boot.nfsroot.server6",
+ &nd->root_saddr6, NULL)) {
+ printf("%s: no IPv6 server\n", __func__);
+ return;
+ }
+ nd->root_saddr6.sin6_port = htons(NFS_PORT);
+ in6addr_to_sockaddr("boot.netif.gateway6",
+ &nd->mygateway6, NULL);
+ }
+#endif
+#if defined(INET6) && defined(INET)
+ else
+#endif
+#ifdef INET
+ if (ipv4) {
+ strlcpy(nd->myif.ifra_name, ifp->if_xname,
+ sizeof(nd->myif.ifra_name));
+ if (inaddr_to_sockaddr("boot.nfsroot.server",
+ &nd->root_saddr)) {
+ printf("%s: no IPv4 server\n", __func__);
+ return;
+ }
+ nd->root_saddr.sin_port = htons(NFS_PORT);
+ inaddr_to_sockaddr("boot.netif.gateway",
+ &nd->mygateway);
+ }
+#endif
/* set up root mount */
nd->root_args.rsize = 8192; /* XXX tunable? */
nd->root_args.wsize = 8192;
nd->root_args.sotype = SOCK_STREAM;
nd->root_args.flags = (NFSMNT_WSIZE |
NFSMNT_RSIZE | NFSMNT_RESVPORT);
- if (inaddr_to_sockaddr("boot.nfsroot.server",
- &nd->root_saddr)) {
- printf("nfs_diskless: no server\n");
- return;
- }
- nd->root_saddr.sin_port = htons(NFS_PORT);
+
if (decode_nfshandle("boot.nfsroot.nfshandle",
&nd->root_fh[0], NFSX_V2FH) == 0) {
- printf("nfs_diskless: no NFS handle\n");
+ printf("%s: no NFS handle\n", __func__);
return;
}
if ((cp = kern_getenv("boot.nfsroot.path")) != NULL) {
@@ -340,27 +483,85 @@
}
}
+#ifdef INET
static int
-inaddr_to_sockaddr(char *ev, struct sockaddr_in *sa)
+inaddr_to_sockaddr(char *ev, struct sockaddr_in *sin)
{
- u_int32_t a[4];
char *cp;
- int count;
+ int rc;
- bzero(sa, sizeof(*sa));
- sa->sin_len = sizeof(*sa);
- sa->sin_family = AF_INET;
+ bzero(sin, sizeof(*sin));
+ sin->sin_len = sizeof(*sin);
+ sin->sin_family = AF_INET;
if ((cp = kern_getenv(ev)) == NULL)
return (1);
- count = sscanf(cp, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
+ rc = inet_pton(AF_INET, cp, &sin->sin_addr);
freeenv(cp);
- if (count != 4)
+ if (rc != 1)
return (1);
- sa->sin_addr.s_addr =
- htonl((a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]);
return (0);
}
+#endif
+
+#ifdef INET6
+static int
+in6addr_to_sockaddr(char *ev, struct sockaddr_in6 *sin6,
+ struct sockaddr_in6 *in6mask)
+{
+ char *cp, *p, *pend;
+ unsigned long l;
+ int rc;
+
+ bzero(sin6, sizeof(*sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_len = sizeof(*sin6);
+
+ if ((cp = kern_getenv(ev)) == NULL)
+ return (1);
+
+ p = strchr(cp, '/');
+ if (p != NULL)
+ *p++ = '\0';
+ rc = inet_pton(AF_INET6, cp, &sin6->sin6_addr);
+ if (rc != 1) {
+ freeenv(cp);
+ return (1);
+ }
+
+ if (in6mask != NULL) {
+ /*
+ * Try to convert the /prefix into something we can
+ * use as a mask.
+ */
+ bzero(in6mask, sizeof(*in6mask));
+ /* We do not set faimly for the mask? */
+ in6mask->sin6_len = sizeof(*in6mask);
+ if (p != NULL && *p != '\0') {
+ l = strtoul(p, &pend, 0);
+ if (l == ULONG_MAX || (l == 0 && pend == p)) {
+ freeenv(cp);
+ return (1);
+ }
+ /* If l > 128, input error, use /64. */
+ if (l > 128)
+ in6mask->sin6_addr = in6mask64;
+ else if (l == 0 || l == 128)
+ in6mask->sin6_addr = in6mask128;
+ else {
+ for (p = (u_char *)&in6mask->sin6_addr; l > 7;
+ l -= 8)
+ *p++ = 0xff;
+ *p = 0xff << (8 - l);
+ }
+ } else
+ in6mask->sin6_addr = in6mask64;
+ }
+ freeenv(cp);
+
+ return (0);
+}
+#endif
static int
hwaddr_to_sockaddr(char *ev, struct sockaddr_dl *sa)
Index: sys/nfs/nfsdiskless.h
===================================================================
--- sys/nfs/nfsdiskless.h
+++ sys/nfs/nfsdiskless.h
@@ -38,7 +38,19 @@
#ifndef _NFSCLIENT_NFSDISKLESS_H_
#define _NFSCLIENT_NFSDISKLESS_H_
+#ifndef _SOCKADDR_UNION_DEFINED
+#define _SOCKADDR_UNION_DEFINED
/*
+ * The union of all possible address formats we handle.
+ */
+union sockaddr_union {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+#endif /* _SOCKADDR_UNION_DEFINED */
+
+/*
* Structure that must be initialized for a diskless nfs client.
* This structure is used by nfs_mountroot() to set up the root vnode,
* and to do a partial ifconfig(8) and route(8) so that the critical net
@@ -59,16 +71,27 @@
* still Version 2 anyhow.)
*/
struct nfsv3_diskless {
- struct ifaliasreq myif; /* Default interface */
- struct sockaddr_in mygateway; /* Default gateway */
+ sa_family_t sa_family;
+ struct ifnet *ifp;
+ union {
+ struct ifaliasreq _myif; /* Default interface */
+ struct in6_aliasreq _myif6;
+ } _lif;
+ union sockaddr_union _mygateway; /* Default gateway */
struct nfs_args root_args; /* Mount args for root fs */
int root_fhsize; /* Size of root file handle */
u_char root_fh[NFSX_V3FHMAX]; /* File handle of root dir */
- struct sockaddr_in root_saddr; /* Address of root server */
+ union sockaddr_union _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 */
};
+#define myif _lif._myif
+#define myif6 _lif._myif6
+#define mygateway _mygateway.sin
+#define mygateway6 _mygateway.sin6
+#define root_saddr _root_saddr.sin
+#define root_saddr6 _root_saddr.sin6
/*
* Old arguments to mount NFS
@@ -94,11 +117,16 @@
};
struct nfs_diskless {
- struct ifaliasreq myif; /* Default interface */
- struct sockaddr_in mygateway; /* Default gateway */
+ sa_family_t sa_family;
+ struct ifnet *ifp;
+ union {
+ struct ifaliasreq _myif; /* Default interface */
+ struct in6_aliasreq _myif6;
+ } _lif;
+ union sockaddr_union _mygateway; /* Default gateway */
struct onfs_args root_args; /* Mount args for root fs */
u_char root_fh[NFSX_V2FH]; /* File handle of root dir */
- struct sockaddr_in root_saddr; /* Address of root server */
+ union sockaddr_union _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 */

File Metadata

Mime Type
text/plain
Expires
Tue, Mar 17, 11:13 PM (10 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
29858077
Default Alt Text
D22487.diff (24 KB)

Event Timeline