X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/de355530ae67247cbd0da700edb3a2a1dae884c2..89b3af67bb32e691275bf6fa803d1834b2284115:/bsd/nfs/nfs_boot.c diff --git a/bsd/nfs/nfs_boot.c b/bsd/nfs/nfs_boot.c index 0590f4c49..9db27d75f 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-2004 Apple Computer, 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(struct nfs_diskless *nd, proc_t procp) { panic("nfs_boot_init: no ether"); } +int nfs_boot_getfh(struct nfs_diskless *nd, proc_t procp, int v3, int sotype) +{ + panic("nfs_boot_getfh: no ether"); +} + #else /* NETHER */ /* @@ -153,17 +160,17 @@ int nfs_boot_init(nd, 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 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_long *fhlenp); /* other helpers */ -static int 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" @@ -182,18 +189,19 @@ 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, __unused proc_t procp) { struct sockaddr_in bp_sin; boolean_t do_bpwhoami = TRUE; boolean_t do_bpgetfile = TRUE; int error = 0; struct in_addr my_ip; - char * root_path = NULL; struct sockaddr_in * sin_p; + /* make sure mbuf constants are set up */ + if (!nfs_mbuf_mlen) + 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"); @@ -202,21 +210,24 @@ nfs_boot_init(nd, procp) } /* get the root path information */ - MALLOC(root_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); + 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; + } 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), - root_path, MAXPATHLEN) == TRUE) { + nd->nd_root.ndm_path, MAXPATHLEN) == TRUE) { do_bpgetfile = FALSE; do_bpwhoami = FALSE; } nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; - thread_funnel_switch(KERNEL_FUNNEL, NETWORK_FUNNEL); - if (do_bpwhoami) { struct in_addr router; /* @@ -244,68 +255,94 @@ nfs_boot_init(nd, procp) } if (do_bpgetfile) { error = bp_getfile(&bp_sin, "root", &nd->nd_root.ndm_saddr, - nd->nd_root.ndm_host, root_path); + nd->nd_root.ndm_host, nd->nd_root.ndm_path); if (error) { printf("nfs_boot: bootparam get root: %d\n", error); goto failed; } } - - error = get_file_handle(root_path, &nd->nd_root); - if (error) { - printf("nfs_boot: get_file_handle() root failed, %d\n", error); - goto failed; - } #if !defined(NO_MOUNT_PRIVATE) if (do_bpgetfile) { /* get private path */ - char * private_path = NULL; - - MALLOC(private_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); + 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; + } error = bp_getfile(&bp_sin, "private", &nd->nd_private.ndm_saddr, - nd->nd_private.ndm_host, private_path); + nd->nd_private.ndm_host, + nd->nd_private.ndm_path); if (!error) { char * check_path = NULL; - MALLOC(check_path, char *, MAXPATHLEN, M_TEMP, M_WAITOK); - sprintf(check_path, "%s/private", root_path); + 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, private_path) == 0)) { + && (strcmp(check_path, nd->nd_private.ndm_path) == 0)) { /* private path is prefix of root path, don't mount */ nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; } - else { - error = get_file_handle(private_path, - &nd->nd_private); - if (error) { - printf("nfs_boot: get_file_handle() private failed, %d\n", error); - goto failed; - } - } - _FREE(check_path, M_TEMP); + FREE_ZONE(check_path, MAXPATHLEN, M_NAMEI); } else { /* private key not defined, don't mount */ nd->nd_private.ndm_saddr.sin_addr.s_addr = 0; } - _FREE(private_path, M_TEMP); } else { error = 0; } -#endif NO_MOUNT_PRIVATE - failed: - thread_funnel_switch(NETWORK_FUNNEL, KERNEL_FUNNEL); - _FREE(root_path, M_TEMP); +#endif /* NO_MOUNT_PRIVATE */ +failed: + return (error); +} + +/* + * Called with a partially initialized nfs_diskless struct + * with file handles to be filled in. + */ +int +nfs_boot_getfh(struct nfs_diskless *nd, __unused proc_t procp, int v3, int sotype) +{ + 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; + } + +#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 int -get_file_handle(pathname, ndmntp) - char *pathname; /* path on server */ - struct nfs_dlmount *ndmntp; /* output */ +get_file_handle(ndmntp) + struct nfs_dlmount *ndmntp; { char *sp, *dp, *endp; int error; @@ -314,7 +351,8 @@ 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) return (error); @@ -323,7 +361,7 @@ get_file_handle(pathname, ndmntp) endp = dp + MNAMELEN - 1; dp += strlen(dp); *dp++ = ':'; - for (sp = pathname; *sp && dp < endp;) + for (sp = ndmntp->ndm_path; *sp && dp < endp;) *dp++ = *sp++; *dp = '\0'; return (0); @@ -335,23 +373,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(int 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); } @@ -408,8 +448,8 @@ bp_whoami(bpsin, my_ip, gw_ip) struct rpc_string *str; struct bp_inaddr *bia; - struct mbuf *m; - struct sockaddr_in *sin; + mbuf_t m; + struct sockaddr_in sin; int error, msg_len; int cn_len, dn_len; u_char *p; @@ -419,14 +459,14 @@ bp_whoami(bpsin, my_ip, gw_ip) * 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); @@ -444,32 +484,31 @@ 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)) + if (msg_len < (int)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))) + if (msg_len < (ntohl(*lp) + (int)sizeof(*lp))) goto bad; msg_len = ntohl(*lp++); p = (char*)lp; /* client name */ - if (msg_len < sizeof(*str)) + if (msg_len < (int)sizeof(*str)) goto bad; str = (struct rpc_string *)p; cn_len = ntohl(str->len); @@ -484,7 +523,7 @@ bp_whoami(bpsin, my_ip, gw_ip) msg_len -= RPC_STR_SIZE(cn_len); /* domain name */ - if (msg_len < sizeof(*str)) + if (msg_len < (int)sizeof(*str)) goto bad; str = (struct rpc_string *)p; dn_len = ntohl(str->len); @@ -499,7 +538,7 @@ bp_whoami(bpsin, my_ip, gw_ip) msg_len -= RPC_STR_SIZE(dn_len); /* gateway address */ - if (msg_len < sizeof(*bia)) + if (msg_len < (int)sizeof(*bia)) goto bad; bia = (struct bp_inaddr *)p; if (bia->atype != htonl(1)) @@ -516,10 +555,7 @@ bad: error = EBADRPC; out: - if (sin) - FREE(sin, M_SONAME); - - m_freem(m); + mbuf_freem(m); return(error); } @@ -534,13 +570,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; @@ -555,14 +591,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; @@ -575,7 +611,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; @@ -583,11 +619,11 @@ 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); @@ -601,7 +637,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)) @@ -619,7 +655,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); @@ -636,7 +672,7 @@ bad: error = EBADRPC; out: - m_freem(m); + mbuf_freem(m); return(0); } @@ -647,60 +683,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_long *fhlenp; { /* The RPC structures */ struct rpc_string *str; struct rdata { u_long errno; - u_char fh[NFSX_V2FH]; + u_char data[NFSX_V3FHMAX + sizeof(u_long)]; } *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_long)) 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_long fhlen; + u_char *fh; + if (mlen < (int)sizeof(u_long)*2) + goto bad; + fhlen = ntohl(*(u_long*)rdata->data); + fh = rdata->data + sizeof(u_long); + if (mlen < (int)(sizeof(u_long)*2 + fhlen)) + goto bad; + bcopy(fh, fhp, fhlen); + *fhlenp = fhlen; + } else { + if (mlen < ((int)sizeof(u_long) + 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; }