X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..15129b1c8dbb3650c63b70adb1cad9af601c6c17:/bsd/nfs/nfs_boot.c?ds=inline diff --git a/bsd/nfs/nfs_boot.c b/bsd/nfs/nfs_boot.c index f7849b02d..7fcd73bee 100644 --- a/bsd/nfs/nfs_boot.c +++ b/bsd/nfs/nfs_boot.c @@ -1,23 +1,29 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2008 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. * - * @APPLE_LICENSE_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* Copyright (c) 1995, 1997 NeXT Computer, Inc. All Rights Reserved */ /* @@ -92,12 +98,11 @@ #include #include #include -#include -#include +#include +#include #include #include -#include #include #include @@ -119,17 +124,19 @@ #include -extern char *strchr(const char *str, int ch); #if NETHER == 0 -int nfs_boot_init(nd, procp) - struct nfs_diskless *nd; - struct proc *procp; +int nfs_boot_init(__unused struct nfs_diskless *nd) { panic("nfs_boot_init: no ether"); } +int nfs_boot_getfh(__unused struct nfs_diskless *nd, __unused int v3, __unused int sotype) +{ + panic("nfs_boot_getfh: no ether"); +} + #else /* NETHER */ /* @@ -152,438 +159,196 @@ int nfs_boot_init(nd, procp) * (This happens to be the way Sun does it too.) */ -extern int bootp(struct ifnet * ifp, struct in_addr * iaddr_p, int max_retry, - struct in_addr * netmask_p, struct in_addr * router_p, - struct proc * procp); - /* bootparam RPC */ -static int bp_whoami __P((struct sockaddr_in *bpsin, - struct in_addr *my_ip, struct in_addr *gw_ip)); -static int bp_getfile __P((struct sockaddr_in *bpsin, char *key, - struct sockaddr_in *mdsin, char *servname, char *path)); - -static boolean_t path_getfile __P((char * image_path, - struct sockaddr_in * sin_p, - char * serv_name, char * pathname)); - -static __inline__ -u_long iptohl(struct in_addr ip) -{ - return (ntohl(ip.s_addr)); -} - -static __inline__ boolean_t -same_subnet(struct in_addr addr1, struct in_addr addr2, struct in_addr mask) -{ - u_long m = iptohl(mask); - if ((iptohl(addr1) & m) != (iptohl(addr2) & m)) - return (FALSE); - return (TRUE); -} +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, const char *key, + struct sockaddr_in *mdsin, char *servname, char *path); /* mountd RPC */ -static int md_mount __P((struct sockaddr_in *mdsin, char *path, - u_char *fh)); +static int md_mount(struct sockaddr_in *mdsin, char *path, int v3, int sotype, + u_char *fhp, u_int32_t *fhlenp); /* other helpers */ -static void get_file_handle __P((char *pathname, struct nfs_dlmount *ndmntp)); +static int get_file_handle(struct nfs_dlmount *ndmntp); + #define IP_FORMAT "%d.%d.%d.%d" #define IP_CH(ip) ((u_char *)ip) #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3] + +#include + /* * Called with an empty nfs_diskless struct to be filled in. */ int -nfs_boot_init(nd, procp) - struct nfs_diskless *nd; - struct proc *procp; +nfs_boot_init(struct nfs_diskless *nd) { - char * booter_path = NULL; - boolean_t do_bpwhoami = TRUE; - boolean_t do_bpgetfile = TRUE; - struct ifreq ireq; - struct in_addr my_ip; - struct sockaddr_in bp_sin; - struct sockaddr_in *sin; - struct ifnet *ifp; - struct in_addr gw_ip; - struct socket *so; - struct in_addr my_netmask; - int error; - char * root_path = NULL; - - MALLOC(booter_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); - MALLOC(root_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); - - /* booter-supplied path */ - if (!PE_parse_boot_arg("rp", booter_path) - && !PE_parse_boot_arg("rootpath", booter_path)) { - booter_path[0] = 0; + struct sockaddr_in bp_sin; + boolean_t do_bpwhoami = TRUE; + boolean_t do_bpgetfile = TRUE; + int error = 0; + struct in_addr my_ip; + struct sockaddr_in * sin_p; + + /* make sure mbuf constants are set up */ + if (!nfs_mbuf_mhlen) + nfs_mbuf_init(); + + /* by this point, networking must already have been configured */ + if (netboot_iaddr(&my_ip) == FALSE) { + printf("nfs_boot: networking is not initialized\n"); + error = ENXIO; + goto failed; } - root_path[0] = 0; - - gw_ip.s_addr = 0; - - /* clear out the request structure */ - bzero(&ireq, sizeof(ireq)); - - /* - * 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.) - */ - - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - - /* - * Find a network interface. - */ - ifp = NULL; - { /* if the root device is set, use it */ - extern char rootdevice[]; - if (rootdevice[0]) - ifp = ifunit(rootdevice); - } - if (ifp == NULL) { /* search for network device */ - /* for (ifp = ifnet; ifp; ifp = ifp->if_next)*/ - TAILQ_FOREACH(ifp, &ifnet, if_link) - if ((ifp->if_flags & - (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0) - break; + /* get the root path information */ + MALLOC_ZONE(nd->nd_root.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + if (!nd->nd_root.ndm_path) { + printf("nfs_boot: can't allocate root path buffer\n"); + error = ENOMEM; + goto failed; } - 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 = ifp->if_flags | IFF_UP; - error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)&ireq, procp); - if (error) - panic("nfs_boot: SIFFLAGS, error=%d", error); - -#define DO_BOOTP -#ifdef DO_BOOTP - { /* use BOOTP to retrieve IP address, netmask and router */ - struct sockaddr_in sockin; - struct in_addr router; - struct in_addr netmask; - - my_ip.s_addr = 0; - netmask.s_addr = 0; - router.s_addr = 0; - sockin.sin_family = AF_INET; - sockin.sin_len = sizeof(sockin); - sockin.sin_addr.s_addr = 0; -#define RETRY_COUNT 32 - while ((error = bootp(ifp, &my_ip, RETRY_COUNT, - &netmask, &router, procp))) { - if (error == ETIMEDOUT) - printf("nfs_boot: BOOTP timed out, retrying...\n"); - - else { - printf("nfs_boot: bootp() failed, error = %d\n", error); - panic("nfs_boot"); - } - } - /* clear the netmask */ - ((struct sockaddr_in *)&ireq.ifr_addr)->sin_addr.s_addr = 0; - error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)&ireq, procp); - if (error) - printf("nfs_boot: SIOCSIFNETMASK failed: %d\n", error); - - if (netmask.s_addr) { - /* set our new subnet mask */ - sockin.sin_addr = netmask; - *((struct sockaddr_in *)&ireq.ifr_addr) = sockin; - error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)&ireq, procp); - if (error) - printf("nfs_boot: SIOCSIFNETMASK failed: %d\n", error); - } - - /* set our address */ - sockin.sin_addr = my_ip; - *((struct sockaddr_in *)&ireq.ifr_addr) = sockin; - error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ireq, procp); - if (error) { - printf("SIOCSIFADDR failed: %d\n", error); - panic("nfs_boot.c"); - } - printf("nfs_boot: IP address " IP_FORMAT, IP_LIST(&my_ip)); - if (netmask.s_addr) - printf(" netmask " IP_FORMAT, IP_LIST(&netmask)); - if (router.s_addr) { - gw_ip = router; - printf(" router " IP_FORMAT, IP_LIST(&router)); - } - printf("\n"); + MALLOC_ZONE(nd->nd_root.ndm_mntfrom, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + if (!nd->nd_root.ndm_mntfrom) { + printf("nfs_boot: can't allocate root mntfrom buffer\n"); + error = ENOMEM; + goto failed; } -#else - /* - * Do RARP for the interface address. - */ - if ((error = revarpwhoami(&my_ip, ifp)) != 0) - panic("revarp failed, error=%d", error); - printf("nfs_boot: client_addr=0x%x\n", ntohl(my_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; - bzero((caddr_t)sin, sizeof(*sin)); - 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); -#endif DO_BOOTP - - /* need netmask to determine whether NFS server local */ - sin = (struct sockaddr_in *)&ireq.ifr_addr; - bzero((caddr_t)sin, sizeof(*sin)); - sin->sin_len = sizeof(*sin); - sin->sin_family = AF_INET; - error = ifioctl(so, SIOCGIFNETMASK, (caddr_t)&ireq, procp); - if (error) - panic("nfs_boot: SIOCGIFNETMASK error=%d", error); - my_netmask = sin->sin_addr; - - soclose(so); - - /* check for a booter-specified path */ - if (booter_path[0]) { - nd->nd_root.ndm_saddr.sin_addr.s_addr = 0; - nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; - if (path_getfile(booter_path, &nd->nd_root.ndm_saddr, - nd->nd_root.ndm_host, root_path)) { - do_bpgetfile = FALSE; - printf("nfs_boot: using booter-supplied path '%s'\n", - booter_path); - if (same_subnet(nd->nd_root.ndm_saddr.sin_addr, - my_ip, my_netmask) - || gw_ip.s_addr) { - do_bpwhoami = FALSE; - } - else { - /* do bpwhoami to attempt to get the router */ - } - } - else { - printf("nfs_boot: ignoring badly formed bootpath '%s'\n", - booter_path); - } + sin_p = &nd->nd_root.ndm_saddr; + bzero((caddr_t)sin_p, sizeof(*sin_p)); + sin_p->sin_len = sizeof(*sin_p); + sin_p->sin_family = AF_INET; + if (netboot_rootpath(&sin_p->sin_addr, nd->nd_root.ndm_host, + sizeof(nd->nd_root.ndm_host), + nd->nd_root.ndm_path, MAXPATHLEN) == TRUE) { + do_bpgetfile = FALSE; + do_bpwhoami = FALSE; } + nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; if (do_bpwhoami) { - /* - * Get client name and gateway address. - * RPC: bootparam/whoami - * Use the old broadcast address for the WHOAMI - * call because we do not yet know our netmask. - * The server address returned by the WHOAMI call - * is used for all subsequent booptaram RPCs. - */ - bzero((caddr_t)&bp_sin, sizeof(bp_sin)); - bp_sin.sin_len = sizeof(bp_sin); - bp_sin.sin_family = AF_INET; - bp_sin.sin_addr.s_addr = INADDR_BROADCAST; - hostnamelen = MAXHOSTNAMELEN; - - { /* bpwhoami also returns gateway IP address */ - struct in_addr router; - + /* + * Get client name and gateway address. + * RPC: bootparam/whoami + * Use the old broadcast address for the WHOAMI + * call because we do not yet know our netmask. + * The server address returned by the WHOAMI call + * is used for all subsequent booptaram RPCs. + */ + bzero((caddr_t)&bp_sin, sizeof(bp_sin)); + bp_sin.sin_len = sizeof(bp_sin); + bp_sin.sin_family = AF_INET; + bp_sin.sin_addr.s_addr = INADDR_BROADCAST; + hostnamelen = MAXHOSTNAMELEN; router.s_addr = 0; error = bp_whoami(&bp_sin, &my_ip, &router); if (error) { - printf("nfs_boot: bootparam whoami, error=%d", error); - panic("nfs_boot: bootparam whoami\n"); + printf("nfs_boot: bootparam whoami, error=%d", error); + goto failed; } - /* if not already set by BOOTP, use the one from BPWHOAMI */ - if (gw_ip.s_addr == 0) - gw_ip = router; - } - printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n", - IP_LIST(&bp_sin.sin_addr)); - printf("nfs_boot: hostname %s\n", hostname); - } -#define NFS_BOOT_GATEWAY 1 -#ifdef NFS_BOOT_GATEWAY - /* - * DWS 2/18/1999 - * The comment below does not apply to gw_ip discovered - * via BOOTP (see DO_BOOTP loop above) since BOOTP servers - * are supposed to be more trustworthy. - */ - /* - * XXX - This code is conditionally compiled only because - * many bootparam servers (in particular, SunOS 4.1.3) - * always set the gateway address to their own address. - * The bootparam server is not necessarily the gateway. - * We could just believe the server, and at worst you would - * need to delete the incorrect default route before adding - * the correct one, but for simplicity, ignore the gateway. - * 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) { - struct sockaddr dst, gw, mask; - /* Destination: (default) */ - bzero((caddr_t)&dst, sizeof(dst)); - dst.sa_len = sizeof(dst); - dst.sa_family = AF_INET; - /* Gateway: */ - bzero((caddr_t)&gw, sizeof(gw)); - sin = (struct sockaddr_in *)&gw; - sin->sin_len = sizeof(gw); - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = gw_ip.s_addr; - /* Mask: (zero length) */ - bzero(&mask, sizeof(mask)); - printf("nfs_boot: adding default route " IP_FORMAT "\n", - IP_LIST(&gw_ip)); - /* add, dest, gw, mask, flags, 0 */ - error = rtrequest(RTM_ADD, &dst, (struct sockaddr *)&gw, - &mask, (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL); - if (error) - printf("nfs_boot: add route, error=%d\n", error); + printf("nfs_boot: BOOTPARAMS server " IP_FORMAT "\n", + IP_LIST(&bp_sin.sin_addr)); + printf("nfs_boot: hostname %s\n", hostname); } -#endif if (do_bpgetfile) { - error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr, - nd->nd_root.ndm_host, root_path); - if (error) { - printf("nfs_boot: bootparam get root: %d\n", error); - panic("nfs_boot: bootparam get root"); - } + error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr, + nd->nd_root.ndm_host, nd->nd_root.ndm_path); + if (error) { + printf("nfs_boot: bootparam get root: %d\n", error); + goto failed; + } } - get_file_handle(root_path, &nd->nd_root); - #if !defined(NO_MOUNT_PRIVATE) if (do_bpgetfile) { /* get private path */ - char * private_path = NULL; - - MALLOC(private_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); - error = bp_getfile(&bp_sin, "private", - &nd->nd_private.ndm_saddr, - nd->nd_private.ndm_host, private_path); - if (!error) { - char * check_path = NULL; - - MALLOC(check_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); - sprintf(check_path, "%s/private", root_path); - if ((nd->nd_root.ndm_saddr.sin_addr.s_addr - == nd->nd_private.ndm_saddr.sin_addr.s_addr) - && (strcmp(check_path, private_path) == 0)) { - /* private path is prefix of root path, don't mount */ - nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; + MALLOC_ZONE(nd->nd_private.ndm_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + if (!nd->nd_private.ndm_path) { + printf("nfs_boot: can't allocate private path buffer\n"); + error = ENOMEM; + goto failed; + } + MALLOC_ZONE(nd->nd_private.ndm_mntfrom, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + if (!nd->nd_private.ndm_mntfrom) { + printf("nfs_boot: can't allocate private host buffer\n"); + error = ENOMEM; + goto failed; + } + error = bp_getfile(&bp_sin, "private", + &nd->nd_private.ndm_saddr, + nd->nd_private.ndm_host, + nd->nd_private.ndm_path); + if (!error) { + char * check_path = NULL; + + MALLOC_ZONE(check_path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); + if (!check_path) { + printf("nfs_boot: can't allocate check_path buffer\n"); + error = ENOMEM; + goto failed; + } + snprintf(check_path, MAXPATHLEN, "%s/private", nd->nd_root.ndm_path); + if ((nd->nd_root.ndm_saddr.sin_addr.s_addr + == nd->nd_private.ndm_saddr.sin_addr.s_addr) + && (strncmp(check_path, nd->nd_private.ndm_path, MAXPATHLEN) == 0)) { + /* private path is prefix of root path, don't mount */ + nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; + } + FREE_ZONE(check_path, MAXPATHLEN, M_NAMEI); } - else { - get_file_handle(private_path, &nd->nd_private); + else { + /* private key not defined, don't mount */ + nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; } - _FREE(check_path, M_TEMP); - } - else { - /* private key not defined, don't mount */ - nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; - } - _FREE(private_path, M_TEMP); } -#endif NO_MOUNT_PRIVATE - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - _FREE(booter_path, M_TEMP); - _FREE(root_path, M_TEMP); - return (0); -} - -int -inet_aton(char * cp, struct in_addr * pin) -{ - u_char * b = (char *)pin; - int i; - char * p; - - for (p = cp, i = 0; i < 4; i++) { - u_long l = strtoul(p, 0, 0); - if (l > 255) - return (FALSE); - b[i] = l; - p = strchr(p, '.'); - if (i < 3 && p == NULL) - return (FALSE); - p++; - } - return (TRUE); + else { + error = 0; + } +#endif /* NO_MOUNT_PRIVATE */ +failed: + return (error); } /* - * Function: parse_image_path - * Purpose: - * Parse a string of the form "::" into - * the given ip address and host and pathnames. - * Example: - * "17.202.16.17:seaport:/release/.images/Image9/CurrentHera" + * Called with a partially initialized nfs_diskless struct + * with file handles to be filled in. */ -static __inline__ boolean_t -parse_image_path(char * c, struct in_addr * iaddr_p, char * hostname, - char * pathname) +int +nfs_boot_getfh(struct nfs_diskless *nd, int v3, int sotype) { - char * d; - char * p; -#define TMP_SIZE 128 - char tmp[TMP_SIZE]; - - p = strchr(c, ':'); - if (p == NULL) - return (FALSE); - if ((p - c) >= TMP_SIZE) - return (FALSE); - strncpy(tmp, c, p - c); - tmp[p - c] = 0; - if (inet_aton(tmp, iaddr_p) != 1) - return (FALSE); - p++; - d = strchr(p, ':'); - if (d == NULL) - return (FALSE); - strncpy(hostname, p, d - p); - hostname[d - p] = 0; - d++; - strcpy(pathname, d); - return (TRUE); -} + int error = 0; + + nd->nd_root.ndm_nfsv3 = v3; + nd->nd_root.ndm_sotype = sotype; + error = get_file_handle(&nd->nd_root); + if (error) { + printf("nfs_boot: get_file_handle(v%d) root failed, %d\n", + v3 ? 3 : 2, error); + goto failed; + } -static boolean_t -path_getfile(char * image_path, struct sockaddr_in * sin_p, - char * serv_name, char * pathname) -{ - bzero((caddr_t)sin_p, sizeof(*sin_p)); - sin_p->sin_len = sizeof(*sin_p); - sin_p->sin_family = AF_INET; - if (parse_image_path(image_path, &sin_p->sin_addr, serv_name, pathname) - == FALSE) - return (FALSE); - return (TRUE); +#if !defined(NO_MOUNT_PRIVATE) + if (nd->nd_private.ndm_saddr.sin_addr.s_addr) { + /* get private file handle */ + nd->nd_private.ndm_nfsv3 = v3; + nd->nd_private.ndm_sotype = sotype; + error = get_file_handle(&nd->nd_private); + if (error) { + printf("nfs_boot: get_file_handle(v%d) private failed, %d\n", + v3 ? 3 : 2, error); + goto failed; + } + } +#endif /* NO_MOUNT_PRIVATE */ +failed: + return (error); } -static void -get_file_handle(pathname, ndmntp) - char *pathname; /* path on server */ - struct nfs_dlmount *ndmntp; /* output */ +static int +get_file_handle(ndmntp) + struct nfs_dlmount *ndmntp; { char *sp, *dp, *endp; int error; @@ -592,18 +357,22 @@ get_file_handle(pathname, ndmntp) * Get file handle for "key" (root or swap) * using RPC to mountd/mount */ - error = md_mount(&ndmntp->ndm_saddr, pathname, ndmntp->ndm_fh); + error = md_mount(&ndmntp->ndm_saddr, ndmntp->ndm_path, ndmntp->ndm_nfsv3, + ndmntp->ndm_sotype, ndmntp->ndm_fh, &ndmntp->ndm_fhlen); if (error) - panic("nfs_boot: mountd, error=%d", error); + return (error); /* Construct remote path (for getmntinfo(3)) */ - dp = ndmntp->ndm_host; - endp = dp + MNAMELEN - 1; - dp += strlen(dp); - *dp++ = ':'; - for (sp = pathname; *sp && dp < endp;) + dp = ndmntp->ndm_mntfrom; + endp = dp + MAXPATHLEN - 1; + for (sp = ndmntp->ndm_host; *sp && dp < endp;) + *dp++ = *sp++; + if (dp < endp) + *dp++ = ':'; + for (sp = ndmntp->ndm_path; *sp && dp < endp;) *dp++ = *sp++; *dp = '\0'; + return (0); } @@ -612,23 +381,25 @@ get_file_handle(pathname, ndmntp) * Get an mbuf with the given length, and * initialize the pkthdr length field. */ -static struct mbuf * -m_get_len(int msg_len) +static int +mbuf_get_with_len(size_t msg_len, mbuf_t *m) { - struct mbuf *m; - m = m_gethdr(M_WAIT, MT_DATA); - if (m == NULL) - return NULL; - if (msg_len > MHLEN) { - if (msg_len > MCLBYTES) + int error; + error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, m); + if (error) + return (error); + if (msg_len > mbuf_maxlen(*m)) { + error = mbuf_mclget(MBUF_WAITOK, MBUF_TYPE_DATA, m); + if (error) { + mbuf_freem(*m); + return (error); + } + if (msg_len > mbuf_maxlen(*m)) 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); + mbuf_setlen(*m, msg_len); + mbuf_pkthdr_setlen(*m, msg_len); + return (0); } @@ -636,7 +407,7 @@ m_get_len(int msg_len) * String representation for RPC. */ struct rpc_string { - u_long len; /* length without null or padding */ + u_int32_t len; /* length without null or padding */ u_char data[4]; /* data (longer, of course) */ /* data is padded to a long-word boundary */ }; @@ -645,11 +416,11 @@ struct rpc_string { /* * Inet address in RPC messages - * (Note, really four longs, NOT chars. Blech.) + * (Note, really four 32-bit ints, NOT chars. Blech.) */ struct bp_inaddr { - u_long atype; - long addr[4]; + u_int32_t atype; + int32_t addr[4]; }; @@ -676,34 +447,34 @@ bp_whoami(bpsin, my_ip, gw_ip) { /* RPC structures for PMAPPROC_CALLIT */ struct whoami_call { - u_long call_prog; - u_long call_vers; - u_long call_proc; - u_long call_arglen; + u_int32_t call_prog; + u_int32_t call_vers; + u_int32_t call_proc; + u_int32_t call_arglen; struct bp_inaddr call_ia; } *call; struct rpc_string *str; struct bp_inaddr *bia; - struct mbuf *m; - struct sockaddr_in *sin; - int error, msg_len; - int cn_len, dn_len; + mbuf_t m; + struct sockaddr_in sin; + int error; + size_t msg_len, cn_len, dn_len; u_char *p; - long *lp; + int32_t *lp; /* * Get message buffer of sufficient size. */ msg_len = sizeof(*call); - m = m_get_len(msg_len); - if (m == NULL) - return ENOBUFS; + error = mbuf_get_with_len(msg_len, &m); + if (error) + return error; /* * Build request message for PMAPPROC_CALLIT. */ - call = mtod(m, struct whoami_call *); + call = mbuf_data(m); call->call_prog = htonl(BOOTPARAM_PROG); call->call_vers = htonl(BOOTPARAM_VERS); call->call_proc = htonl(BOOTPARAM_WHOAMI); @@ -721,29 +492,28 @@ bp_whoami(bpsin, my_ip, gw_ip) /* RPC: portmap/callit */ bpsin->sin_port = htons(PMAPPORT); - error = krpc_call(bpsin, PMAPPROG, PMAPVERS, - PMAPPROC_CALLIT, &m, &sin); + error = krpc_call(bpsin, SOCK_DGRAM, PMAPPROG, PMAPVERS, PMAPPROC_CALLIT, &m, &sin); if (error) return error; /* * Parse result message. */ - msg_len = m->m_len; - lp = mtod(m, long *); + msg_len = mbuf_len(m); + lp = mbuf_data(m); /* bootparam server port (also grab from address). */ if (msg_len < sizeof(*lp)) goto bad; msg_len -= sizeof(*lp); bpsin->sin_port = htons((short)ntohl(*lp++)); - bpsin->sin_addr.s_addr = sin->sin_addr.s_addr; + bpsin->sin_addr.s_addr = sin.sin_addr.s_addr; /* length of encapsulated results */ if (msg_len < (ntohl(*lp) + sizeof(*lp))) goto bad; msg_len = ntohl(*lp++); - p = (char*)lp; + p = (u_char*)lp; /* client name */ if (msg_len < sizeof(*str)) @@ -793,10 +563,7 @@ bad: error = EBADRPC; out: - if (sin) - FREE(sin, M_SONAME); - - m_freem(m); + mbuf_freem(m); return(error); } @@ -811,13 +578,13 @@ out: static int bp_getfile(bpsin, key, md_sin, serv_name, pathname) struct sockaddr_in *bpsin; - char *key; + const char *key; struct sockaddr_in *md_sin; char *serv_name; char *pathname; { struct rpc_string *str; - struct mbuf *m; + mbuf_t m; struct bp_inaddr *bia; struct sockaddr_in *sin; u_char *p, *q; @@ -832,14 +599,14 @@ bp_getfile(bpsin, key, md_sin, serv_name, pathname) 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; + error = mbuf_get_with_len(msg_len, &m); + if (error) + return error; /* * Build request message. */ - p = mtod(m, u_char *); + p = mbuf_data(m); bzero(p, msg_len); /* client name (hostname) */ str = (struct rpc_string *)p; @@ -852,7 +619,7 @@ bp_getfile(bpsin, key, md_sin, serv_name, pathname) bcopy(key, str->data, key_len); /* RPC: bootparam/getfile */ - error = krpc_call(bpsin, BOOTPARAM_PROG, BOOTPARAM_VERS, + error = krpc_call(bpsin, SOCK_DGRAM, BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE, &m, NULL); if (error) return error; @@ -860,17 +627,17 @@ bp_getfile(bpsin, key, md_sin, serv_name, pathname) /* * Parse result message. */ - p = mtod(m, u_char *); - msg_len = m->m_len; + p = mbuf_data(m); + msg_len = mbuf_len(m); /* server name */ - if (msg_len < sizeof(*str)) + if (msg_len < (int)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) + if (sn_len >= MAXHOSTNAMELEN) goto bad; bcopy(str->data, serv_name, sn_len); serv_name[sn_len] = '\0'; @@ -878,7 +645,7 @@ bp_getfile(bpsin, key, md_sin, serv_name, pathname) msg_len -= RPC_STR_SIZE(sn_len); /* server IP address (mountd) */ - if (msg_len < sizeof(*bia)) + if (msg_len < (int)sizeof(*bia)) goto bad; bia = (struct bp_inaddr *)p; if (bia->atype != htonl(1)) @@ -896,7 +663,7 @@ bp_getfile(bpsin, key, md_sin, serv_name, pathname) msg_len -= sizeof(*bia); /* server pathname */ - if (msg_len < sizeof(*str)) + if (msg_len < (int)sizeof(*str)) goto bad; str = (struct rpc_string *)p; path_len = ntohl(str->len); @@ -913,7 +680,7 @@ bad: error = EBADRPC; out: - m_freem(m); + mbuf_freem(m); return(0); } @@ -924,60 +691,94 @@ out: * Also, sets sin->sin_port to the NFS service port. */ static int -md_mount(mdsin, path, fhp) +md_mount(mdsin, path, v3, sotype, fhp, fhlenp) struct sockaddr_in *mdsin; /* mountd server address */ char *path; + int v3; + int sotype; u_char *fhp; + u_int32_t *fhlenp; { /* The RPC structures */ struct rpc_string *str; struct rdata { - u_long errno; - u_char fh[NFSX_V2FH]; + u_int32_t errno; + u_char data[NFSX_V3FHMAX + sizeof(u_int32_t)]; } *rdata; - struct mbuf *m; + mbuf_t m; int error, mlen, slen; + int mntversion = v3 ? RPCMNT_VER3 : RPCMNT_VER1; + int proto = (sotype == SOCK_STREAM) ? IPPROTO_TCP : IPPROTO_UDP; + in_port_t mntport, nfsport; /* Get port number for MOUNTD. */ - error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1, - &mdsin->sin_port); - if (error) return error; + error = krpc_portmap(mdsin, RPCPROG_MNT, mntversion, proto, &mntport); + if (error) + return error; + + /* Get port number for NFS use. */ + /* (If NFS/proto unavailable, don't bother with the mount call) */ + error = krpc_portmap(mdsin, NFS_PROG, v3 ? NFS_VER3 : NFS_VER2, proto, &nfsport); + if (error) + return error; + + /* Set port number for MOUNTD */ + mdsin->sin_port = mntport; slen = strlen(path); mlen = RPC_STR_SIZE(slen); - m = m_get_len(mlen); - if (m == NULL) - return ENOBUFS; - str = mtod(m, struct rpc_string *); + error = mbuf_get_with_len(mlen, &m); + if (error) + return error; + str = mbuf_data(m); str->len = htonl(slen); bcopy(path, str->data, slen); /* Do RPC to mountd. */ - error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1, - RPCMNT_MOUNT, &m, NULL); + error = krpc_call(mdsin, sotype, RPCPROG_MNT, mntversion, RPCMNT_MOUNT, &m, NULL); if (error) return error; /* message already freed */ - mlen = m->m_len; - if (mlen < sizeof(*rdata)) + /* + * the reply must be long enough to hold the errno plus either of: + * + a v2 filehandle + * + a v3 filehandle length + a v3 filehandle + */ + mlen = mbuf_len(m); + if (mlen < (int)sizeof(u_int32_t)) goto bad; - rdata = mtod(m, struct rdata *); + rdata = mbuf_data(m); error = ntohl(rdata->errno); if (error) - goto bad; - bcopy(rdata->fh, fhp, NFSX_V2FH); + goto out; + if (v3) { + u_int32_t fhlen; + u_char *fh; + if (mlen < (int)sizeof(u_int32_t)*2) + goto bad; + fhlen = ntohl(*(u_int32_t*)rdata->data); + fh = rdata->data + sizeof(u_int32_t); + if (mlen < (int)(sizeof(u_int32_t)*2 + fhlen)) + goto bad; + bcopy(fh, fhp, fhlen); + *fhlenp = fhlen; + } else { + if (mlen < ((int)sizeof(u_int32_t) + NFSX_V2FH)) + goto bad; + bcopy(rdata->data, fhp, NFSX_V2FH); + *fhlenp = NFSX_V2FH; + } /* Set port number for NFS use. */ - error = krpc_portmap(mdsin, NFS_PROG, NFS_VER2, - &mdsin->sin_port); + mdsin->sin_port = nfsport; goto out; bad: error = EBADRPC; out: - m_freem(m); + mbuf_freem(m); return error; }