X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/d7e50217d7adf6e52786a38bcaa4cd698cb9a79e..060df5ea7c632b1ac8cc8aac1fb59758165c2084:/bsd/nfs/nfs_boot.c diff --git a/bsd/nfs/nfs_boot.c b/bsd/nfs/nfs_boot.c index cec8ac1e8..33bc25128 100644 --- a/bsd/nfs/nfs_boot.c +++ b/bsd/nfs/nfs_boot.c @@ -1,16 +1,19 @@ /* - * Copyright (c) 2000-2002 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2008 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ - * - * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * * 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. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * 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. + * + * 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 @@ -20,7 +23,7 @@ * 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 */ /* @@ -95,12 +98,11 @@ #include #include #include -#include -#include +#include +#include #include #include -#include #include #include @@ -122,21 +124,15 @@ #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(nd, procp, v3) - struct nfs_diskless *nd; - struct proc *procp; - int v3; +int nfs_boot_getfh(__unused struct nfs_diskless *nd, __unused int v3, __unused int sotype) { panic("nfs_boot_getfh: no ether"); } @@ -164,17 +160,17 @@ int nfs_boot_getfh(nd, procp, v3) */ /* 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 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, int v3, - u_char *fhp, u_long *fhlenp)); +static int md_mount(struct sockaddr_in *mdsin, char *path, int v3, int sotype, + u_char *fhp, u_int32_t *fhlenp); /* other helpers */ -static int get_file_handle __P((struct nfs_dlmount *ndmntp)); +static int get_file_handle(struct nfs_dlmount *ndmntp); #define IP_FORMAT "%d.%d.%d.%d" @@ -193,9 +189,7 @@ netboot_rootpath(struct in_addr * server_ip, * 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) { struct sockaddr_in bp_sin; boolean_t do_bpwhoami = TRUE; @@ -204,20 +198,35 @@ nfs_boot_init(nd, procp) 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_noswitch; + goto failed; } /* 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; + } + 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; + } 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, + 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; @@ -225,8 +234,6 @@ nfs_boot_init(nd, procp) } nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - if (do_bpwhoami) { struct in_addr router; /* @@ -264,6 +271,17 @@ nfs_boot_init(nd, procp) #if !defined(NO_MOUNT_PRIVATE) if (do_bpgetfile) { /* get private path */ 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, @@ -272,10 +290,15 @@ nfs_boot_init(nd, procp) 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) - && (strcmp(check_path, nd->nd_private.ndm_path) == 0)) { + && (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; } @@ -289,10 +312,8 @@ nfs_boot_init(nd, procp) else { error = 0; } -#endif NO_MOUNT_PRIVATE +#endif /* NO_MOUNT_PRIVATE */ failed: - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); -failed_noswitch: return (error); } @@ -301,16 +322,12 @@ failed_noswitch: * with file handles to be filled in. */ int -nfs_boot_getfh(nd, procp, v3) - struct nfs_diskless *nd; - struct proc *procp; - int v3; +nfs_boot_getfh(struct nfs_diskless *nd, int v3, int sotype) { int error = 0; - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - 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", @@ -322,6 +339,7 @@ nfs_boot_getfh(nd, procp, v3) 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", @@ -329,9 +347,8 @@ nfs_boot_getfh(nd, procp, v3) goto failed; } } -#endif NO_MOUNT_PRIVATE - failed: - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); +#endif /* NO_MOUNT_PRIVATE */ +failed: return (error); } @@ -347,15 +364,17 @@ get_file_handle(ndmntp) * using RPC to mountd/mount */ error = md_mount(&ndmntp->ndm_saddr, ndmntp->ndm_path, ndmntp->ndm_nfsv3, - ndmntp->ndm_fh, &ndmntp->ndm_fhlen); + ndmntp->ndm_sotype, ndmntp->ndm_fh, &ndmntp->ndm_fhlen); if (error) return (error); /* Construct remote path (for getmntinfo(3)) */ - dp = ndmntp->ndm_host; - endp = dp + MNAMELEN - 1; - dp += strlen(dp); - *dp++ = ':'; + 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'; @@ -368,23 +387,25 @@ get_file_handle(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); } @@ -392,7 +413,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 */ }; @@ -401,11 +422,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]; }; @@ -432,34 +453,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); @@ -477,29 +498,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)) @@ -549,10 +569,7 @@ bad: error = EBADRPC; out: - if (sin) - FREE(sin, M_SONAME); - - m_freem(m); + mbuf_freem(m); return(error); } @@ -567,13 +584,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; @@ -588,14 +605,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; @@ -608,7 +625,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; @@ -616,17 +633,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'; @@ -634,7 +651,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)) @@ -652,7 +669,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); @@ -669,7 +686,7 @@ bad: error = EBADRPC; out: - m_freem(m); + mbuf_freem(m); return(0); } @@ -680,41 +697,52 @@ out: * Also, sets sin->sin_port to the NFS service port. */ static int -md_mount(mdsin, path, v3, fhp, fhlenp) +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_long *fhlenp; + u_int32_t *fhlenp; { /* The RPC structures */ struct rpc_string *str; struct rdata { - u_long errno; - u_char data[NFSX_V3FHMAX + sizeof(u_long)]; + 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, mntversion, - &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, mntversion, - RPCMNT_MOUNT, &m, NULL); + error = krpc_call(mdsin, sotype, RPCPROG_MNT, mntversion, RPCMNT_MOUNT, &m, NULL); if (error) return error; /* message already freed */ @@ -723,41 +751,40 @@ md_mount(mdsin, path, v3, fhp, fhlenp) * + a v2 filehandle * + a v3 filehandle length + a v3 filehandle */ - mlen = m->m_len; - if (mlen < sizeof(u_long)) + 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 out; if (v3) { - u_long fhlen; + u_int32_t fhlen; u_char *fh; - if (mlen < sizeof(u_long)*2) + if (mlen < (int)sizeof(u_int32_t)*2) goto bad; - fhlen = ntohl(*(u_long*)rdata->data); - fh = rdata->data + sizeof(u_long); - if (mlen < (sizeof(u_long)*2 + fhlen)) + 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 < (sizeof(u_long) + NFSX_V2FH)) + 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, v3 ? NFS_VER3 : NFS_VER2, - &mdsin->sin_port); + mdsin->sin_port = nfsport; goto out; bad: error = EBADRPC; out: - m_freem(m); + mbuf_freem(m); return error; }