/*
- * Copyright (c) 2000-2015 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <sys/domain.h>
#include <sys/protosw.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <sys/syslog.h>
#include <sys/tprintf.h>
#include <libkern/OSAtomic.h>
#include <nfs/nfsnode.h>
#define NFS_SOCK_DBG(...) NFS_DBG(NFS_FAC_SOCK, 7, ## __VA_ARGS__)
+#define NFS_SOCK_DUMP_MBUF(msg, mb) if (NFS_IS_DBG(NFS_FAC_SOCK, 15)) nfs_dump_mbuf(__func__, __LINE__, (msg), (mb))
/* XXX */
boolean_t current_thread_aborted(void);
* 3 - read
* 4 - write
*/
-static int proct[NFS_NPROCS] = {
- 0, 1, 0, 2, 1, 3, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 0, 0, 0, 0, 0
+static const int proct[] = {
+ [NFSPROC_NULL] = 0,
+ [NFSPROC_GETATTR] = 1,
+ [NFSPROC_SETATTR] = 0,
+ [NFSPROC_LOOKUP] = 2,
+ [NFSPROC_ACCESS] = 1,
+ [NFSPROC_READLINK] = 3,
+ [NFSPROC_READ] = 3,
+ [NFSPROC_WRITE] = 4,
+ [NFSPROC_CREATE] = 0,
+ [NFSPROC_MKDIR] = 0,
+ [NFSPROC_SYMLINK] = 0,
+ [NFSPROC_MKNOD] = 0,
+ [NFSPROC_REMOVE] = 0,
+ [NFSPROC_RMDIR] = 0,
+ [NFSPROC_RENAME] = 0,
+ [NFSPROC_LINK] = 0,
+ [NFSPROC_READDIR] = 3,
+ [NFSPROC_READDIRPLUS] = 3,
+ [NFSPROC_FSSTAT] = 0,
+ [NFSPROC_FSINFO] = 0,
+ [NFSPROC_PATHCONF] = 0,
+ [NFSPROC_COMMIT] = 0,
+ [NFSPROC_NOOP] = 0,
};
/*
p = s;
if (!pathonly) {
- cnt = snprintf(p, size, "%s:", fsl->nl_servers[idx.nli_serv]->ns_name);
+ char *name = fsl->nl_servers[idx.nli_serv]->ns_name;
+ if (name == NULL) {
+ name = "";
+ }
+ if (*name == '\0') {
+ if (*fsl->nl_servers[idx.nli_serv]->ns_addresses[idx.nli_addr]) {
+ name = fsl->nl_servers[idx.nli_serv]->ns_addresses[idx.nli_addr];
+ }
+ cnt = snprintf(p, size, "<%s>:", name);
+ } else {
+ cnt = snprintf(p, size, "%s:", name);
+ }
p += cnt;
size -= cnt;
}
int error = 0, recv = 1;
if (nso->nso_flags & NSO_CONNECTING) {
- NFS_SOCK_DBG("nfs connect - socket %p upcall - connecting\n", nso);
+ NFS_SOCK_DBG("nfs connect - socket %p upcall - connecting flags = %8.8x\n", nso, nso->nso_flags);
wakeup(nso->nso_wake);
return;
}
lck_mtx_unlock(&nso->nso_lock);
return;
}
- NFS_SOCK_DBG("nfs connect - socket %p upcall\n", nso);
+ NFS_SOCK_DBG("nfs connect - socket %p upcall %8.8x\n", nso, nso->nso_flags);
nso->nso_flags |= NSO_UPCALL;
/* loop while we make error-free progress */
m = NULL;
if (nso->nso_sotype == SOCK_STREAM) {
error = nfs_rpc_record_read(so, &nso->nso_rrs, MSG_DONTWAIT, &recv, &m);
+ NFS_SOCK_DBG("nfs_rpc_record_read returned %d recv = %d\n", error, recv);
} else {
rcvlen = 1000000;
error = sock_receivembuf(so, NULL, &m, MSG_DONTWAIT, &rcvlen);
uint32_t reply = 0, rxid = 0, verf_type, verf_len;
uint32_t reply_status, rejected_status, accepted_status;
+ NFS_SOCK_DUMP_MBUF("Got mbuf from ping", m);
nfsm_chain_dissect_init(error, &nmrep, m);
nfsm_chain_get_32(error, &nmrep, rxid);
nfsm_chain_get_32(error, &nmrep, reply);
}
nfsm_chain_get_32(error, &nmrep, accepted_status);
nfsmout_if(error);
+ NFS_SOCK_DBG("Recevied accepted_status of %d nso_version = %d\n", accepted_status, nso->nso_version);
if ((accepted_status == RPC_PROGMISMATCH) && !nso->nso_version) {
uint32_t minvers, maxvers;
nfsm_chain_get_32(error, &nmrep, minvers);
nfsmout:
nso->nso_flags &= ~NSO_PINGING;
if (error) {
+ NFS_SOCK_DBG("nfs upcalled failed for %d program %d vers error = %d\n",
+ nso->nso_protocol, nso->nso_version, error);
nso->nso_error = error;
nso->nso_flags |= NSO_DEAD;
} else {
nso->nso_flags &= ~NSO_UPCALL;
if ((error != EWOULDBLOCK) && (error || !recv)) {
/* problems with the socket... */
+ NFS_SOCK_DBG("connect upcall failed %d\n", error);
nso->nso_error = error ? error : EPIPE;
nso->nso_flags |= NSO_DEAD;
wakeup(nso->nso_wake);
struct nfs_socket *nso;
struct timeval now;
int error;
+#define NFS_SOCKET_DEBUGGING
#ifdef NFS_SOCKET_DEBUGGING
- char naddr[MAX_IPv6_STR_LEN];
+ char naddr[sizeof((struct sockaddr_un *)0)->sun_path];
void *sinaddr;
- if (sa->sa_family == AF_INET) {
- sinaddr = &((struct sockaddr_in*)sa)->sin_addr;
- } else {
- sinaddr = &((struct sockaddr_in6*)sa)->sin6_addr;
- }
- if (inet_ntop(sa->sa_family, sinaddr, naddr, sizeof(naddr)) != naddr) {
- strlcpy(naddr, "<unknown>", sizeof(naddr));
+ switch (sa->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ if (sa->sa_family == AF_INET) {
+ sinaddr = &((struct sockaddr_in*)sa)->sin_addr;
+ } else {
+ sinaddr = &((struct sockaddr_in6*)sa)->sin6_addr;
+ }
+ if (inet_ntop(sa->sa_family, sinaddr, naddr, sizeof(naddr)) != naddr) {
+ strlcpy(naddr, "<unknown>", sizeof(naddr));
+ }
+ break;
+ case AF_LOCAL:
+ strlcpy(naddr, ((struct sockaddr_un *)sa)->sun_path, sizeof(naddr));
+ break;
+ default:
+ strlcpy(naddr, "<unsupported address family>", sizeof(naddr));
+ break;
}
#else
char naddr[1] = { 0 };
microuptime(&now);
nso->nso_timestamp = now.tv_sec;
bcopy(sa, nso->nso_saddr, sa->sa_len);
- if (sa->sa_family == AF_INET) {
- ((struct sockaddr_in*)nso->nso_saddr)->sin_port = htons(port);
- } else if (sa->sa_family == AF_INET6) {
- ((struct sockaddr_in6*)nso->nso_saddr)->sin6_port = htons(port);
+ switch (sa->sa_family) {
+ case AF_INET:
+ case AF_INET6:
+ if (sa->sa_family == AF_INET) {
+ ((struct sockaddr_in*)nso->nso_saddr)->sin_port = htons(port);
+ } else if (sa->sa_family == AF_INET6) {
+ ((struct sockaddr_in6*)nso->nso_saddr)->sin6_port = htons(port);
+ }
+ break;
+ case AF_LOCAL:
+ break;
}
nso->nso_protocol = protocol;
nso->nso_version = vers;
resvport ? "r" : "", port, protocol, vers);
nfs_socket_destroy(nso);
} else {
- NFS_SOCK_DBG("nfs connect %s created socket %p %s type %d%s port %d prot %d %d\n",
+ NFS_SOCK_DBG("nfs connect %s created socket %p <%s> type %d%s port %d prot %d %d\n",
vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, naddr,
sotype, resvport ? "r" : "", port, protocol, vers);
*nsop = nso;
void
nfs_socket_destroy(struct nfs_socket *nso)
{
- struct timespec ts = { 4, 0 };
+ struct timespec ts = { .tv_sec = 4, .tv_nsec = 0 };
+ NFS_SOCK_DBG("Destoring socket %p flags = %8.8x error = %d\n", nso, nso->nso_flags, nso->nso_error);
lck_mtx_lock(&nso->nso_lock);
nso->nso_flags |= NSO_DISCONNECTING;
if (nso->nso_flags & NSO_UPCALL) { /* give upcall a chance to complete */
sock_setsockopt(nso->nso_so, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
}
}
- if (nso->nso_sotype == SOCK_DGRAM) { /* set socket buffer sizes for UDP */
- int reserve = NFS_UDPSOCKBUF;
+ if (nso->nso_sotype == SOCK_DGRAM || nso->nso_saddr->sa_family == AF_LOCAL) { /* set socket buffer sizes for UDP */
+ int reserve = (nso->nso_sotype == SOCK_DGRAM) ? NFS_UDPSOCKBUF : (2 * 1024 * 1024);
sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_SNDBUF, &reserve, sizeof(reserve));
sock_setsockopt(nso->nso_so, SOL_SOCKET, SO_RCVBUF, &reserve, sizeof(reserve));
}
fsl = nmp->nm_locations.nl_locations[nss->nss_nextloc.nli_loc];
fss = fsl->nl_servers[nss->nss_nextloc.nli_serv];
addrstr = fss->ns_addresses[nss->nss_nextloc.nli_addr];
+ NFS_SOCK_DBG("Trying address %s for program %d on port %d\n", addrstr, nss->nss_protocol, nss->nss_port);
+ if (*addrstr == '\0') {
+ /*
+ * We have an unspecified local domain address. We use the program to translate to
+ * a well known local transport address. We only support PMAPROG and NFS for this.
+ */
+ if (nss->nss_protocol == PMAPPROG) {
+ addrstr = (nss->nss_sotype == SOCK_DGRAM) ? RPCB_TICLTS_PATH : RPCB_TICOTSORD_PATH;
+ } else if (nss->nss_protocol == NFS_PROG) {
+ addrstr = nmp->nm_nfs_localport;
+ if (!addrstr || *addrstr == '\0') {
+ addrstr = (nss->nss_sotype == SOCK_DGRAM) ? NFS_TICLTS_PATH : NFS_TICOTSORD_PATH;
+ }
+ }
+ NFS_SOCK_DBG("Calling prog %d with <%s>\n", nss->nss_protocol, addrstr);
+ }
if (!nfs_uaddr2sockaddr(addrstr, (struct sockaddr*)&ss)) {
+ NFS_SOCK_DBG("Could not convert address %s to socket\n", addrstr);
nfs_location_next(&nmp->nm_locations, &nss->nss_nextloc);
nss->nss_addrcnt -= 1;
nss->nss_last = -2;
}
/* Check that socket family is acceptable. */
if (nmp->nm_sofamily && (ss.ss_family != nmp->nm_sofamily)) {
+ NFS_SOCK_DBG("Skipping socket family %d, want mount family %d\n", ss.ss_family, nmp->nm_sofamily);
nfs_location_next(&nmp->nm_locations, &nss->nss_nextloc);
nss->nss_addrcnt -= 1;
nss->nss_last = -2;
nso->nso_wake = nss;
error = sock_setupcall(nso->nso_so, nfs_connect_upcall, nso);
if (error) {
+ NFS_SOCK_DBG("sock_setupcall failed for socket %p setting nfs_connect_upcall error = %d\n", nso, error);
lck_mtx_lock(&nso->nso_lock);
nso->nso_error = error;
nso->nso_flags |= NSO_DEAD;
/* initiate the connection */
nso->nso_flags |= NSO_CONNECTING;
lck_mtx_unlock(&nso->nso_lock);
- NFS_SOCK_DBG("nfs connect %s connecting socket %p\n",
- vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso);
+ NFS_SOCK_DBG("nfs connect %s connecting socket %p %s\n",
+ vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso,
+ nso->nso_saddr->sa_family == AF_LOCAL ? ((struct sockaddr_un*)nso->nso_saddr)->sun_path : "");
error = sock_connect(nso->nso_so, nso->nso_saddr, MSG_DONTWAIT);
+ if (error) {
+ NFS_SOCK_DBG("nfs connect %s connecting socket %p returned %d\n",
+ vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error);
+ }
lck_mtx_lock(&nso->nso_lock);
if (error && (error != EINPROGRESS)) {
nso->nso_error = error;
}
}
lck_mtx_unlock(&nso->nso_lock);
+ NFS_SOCK_DBG("Pinging socket %p %d %d %d\n", nso, nso->nso_sotype, nso->nso_protocol, vers);
error = nfsm_rpchead2(nmp, nso->nso_sotype, nso->nso_protocol, vers, 0, RPCAUTH_SYS,
vfs_context_ucred(vfs_context_kernel()), NULL, NULL, &xid, &mreq);
lck_mtx_lock(&nso->nso_lock);
reqlen += mbuf_len(m);
}
lck_mtx_unlock(&nso->nso_lock);
+ NFS_SOCK_DUMP_MBUF("Sending ping packet", mreq);
error = sock_sendmbuf(nso->nso_so, &msg, mreq, 0, &sentlen);
NFS_SOCK_DBG("nfs connect %s verifying socket %p send rv %d\n",
vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, error);
continue;
}
lck_mtx_unlock(&nso->nso_lock);
- NFS_SOCK_DBG("nfs connect %s reaping socket %p %d\n",
- vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, nso->nso_error);
+ NFS_SOCK_DBG("nfs connect %s reaping socket %p error = %d flags = %8.8x\n",
+ vfs_statfs(nmp->nm_mountp)->f_mntfromname, nso, nso->nso_error, nso->nso_flags);
nfs_socket_search_update_error(nss, nso->nso_error);
TAILQ_REMOVE(&nss->nss_socklist, nso, nso_link);
nss->nss_sockcnt--;
struct sockaddr_storage ss;
struct sockaddr *saddr, *oldsaddr;
sock_upcall upcall;
- struct timeval now, start;
+#if CONFIG_NFS4
+ struct timeval now;
+#endif
+ struct timeval start;
int error, savederror, nfsvers;
int tryv4 = 1;
uint8_t sotype = nmp->nm_sotype ? nmp->nm_sotype : SOCK_STREAM;
/* First time connecting, we may need to negotiate some things */
if (!(nmp->nm_sockflags & NMSOCK_HASCONNECTED)) {
+ NFS_SOCK_DBG("so_family = %d\n", nmp->nm_sofamily);
+ NFS_SOCK_DBG("nfs port = %d local: <%s>\n", nmp->nm_nfsport, nmp->nm_nfs_localport ? nmp->nm_nfs_localport : "");
+ NFS_SOCK_DBG("mount port = %d local: <%s>\n", nmp->nm_mountport, nmp->nm_mount_localport ? nmp->nm_mount_localport : "");
if (!nmp->nm_vers) {
/* No NFS version specified... */
if (!nmp->nm_nfsport || (!NM_OMATTR_GIVEN(nmp, FH) && !nmp->nm_mountport)) {
+#if CONFIG_NFS4
if (PVER2MAJOR(nmp->nm_max_vers) >= NFS_VER4 && tryv4) {
nss.nss_port = NFS_PORT;
nss.nss_protocol = NFS_PROG;
nss.nss_version = 4;
nss.nss_flags |= NSS_FALLBACK2PMAP;
} else {
- /* ...connect to portmapper first if we (may) need any ports. */
- nss.nss_port = PMAPPORT;
- nss.nss_protocol = PMAPPROG;
- nss.nss_version = 0;
- }
+#endif
+ /* ...connect to portmapper first if we (may) need any ports. */
+ nss.nss_port = PMAPPORT;
+ nss.nss_protocol = PMAPPROG;
+ nss.nss_version = 0;
+#if CONFIG_NFS4
+ }
+#endif
} else {
/* ...connect to NFS port first. */
nss.nss_port = nmp->nm_nfsport;
nss.nss_protocol = NFS_PROG;
nss.nss_version = 0;
}
+#if CONFIG_NFS4
} else if (nmp->nm_vers >= NFS_VER4) {
if (tryv4) {
/* For NFSv4, we use the given (or default) port. */
nss.nss_protocol = PMAPPROG;
nss.nss_version = 0;
}
+#endif
} else {
/* For NFSv3/v2... */
if (!nmp->nm_nfsport || (!NM_OMATTR_GIVEN(nmp, FH) && !nmp->nm_mountport)) {
/* We may be speaking to portmap first... to determine port(s). */
if (nso->nso_saddr->sa_family == AF_INET) {
port = ntohs(((struct sockaddr_in*)nso->nso_saddr)->sin_port);
- } else {
+ } else if (nso->nso_saddr->sa_family == AF_INET6) {
port = ntohs(((struct sockaddr_in6*)nso->nso_saddr)->sin6_port);
+ } else if (nso->nso_saddr->sa_family == AF_LOCAL) {
+ if (nso->nso_protocol == PMAPPROG) {
+ port = PMAPPORT;
+ }
}
+
if (port == PMAPPORT) {
/* Use this portmapper port to get the port #s we need. */
NFS_SOCK_DBG("nfs connect %s got portmapper socket %p\n",
((struct sockaddr_in*)&ss)->sin_port = htons(0);
} else if (ss.ss_family == AF_INET6) {
((struct sockaddr_in6*)&ss)->sin6_port = htons(0);
+ } else if (ss.ss_family == AF_LOCAL) {
+ if (((struct sockaddr_un*)&ss)->sun_path[0] == '/') {
+ NFS_SOCK_DBG("Looking up NFS socket over %s\n", ((struct sockaddr_un*)&ss)->sun_path);
+ }
}
for (; nfsvers >= (int)PVER2MAJOR(nmp->nm_min_vers); nfsvers--) {
if (nmp->nm_vers && nmp->nm_vers != nfsvers) {
continue; /* Wrong version */
}
+#if CONFIG_NFS4
if (nfsvers == NFS_VER4 && nso->nso_sotype == SOCK_DGRAM) {
continue; /* NFSv4 does not do UDP */
}
- error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
- nso->nso_so, NFS_PROG, nfsvers,
- (nso->nso_sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP, timeo);
+#endif
+ if (ss.ss_family == AF_LOCAL && nmp->nm_nfs_localport) {
+ struct sockaddr_un *sun = (struct sockaddr_un *)&ss;
+ NFS_SOCK_DBG("Using supplied local address %s for NFS_PROG\n", nmp->nm_nfs_localport);
+ strlcpy(sun->sun_path, nmp->nm_nfs_localport, sizeof(sun->sun_path));
+ error = 0;
+ } else {
+ NFS_SOCK_DBG("Calling Portmap/Rpcbind for NFS_PROG");
+ error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
+ nso->nso_so, NFS_PROG, nfsvers, nso->nso_sotype, timeo);
+ }
if (!error) {
if (ss.ss_family == AF_INET) {
port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
} else if (ss.ss_family == AF_INET6) {
port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
+ } else if (ss.ss_family == AF_LOCAL) {
+ port = ((struct sockaddr_un *)&ss)->sun_path[0] ? NFS_PORT : 0;
}
if (!port) {
error = EPROGUNAVAIL;
}
+#if CONFIG_NFS4
if (port == NFS_PORT && nfsvers == NFS_VER4 && tryv4 == 0) {
continue; /* We already tried this */
}
+#endif
}
if (!error) {
break;
if (error) {
nfs_socket_search_update_error(&nss, error);
nfs_socket_destroy(nso);
+ NFS_SOCK_DBG("Could not lookup NFS socket address for version %d error = %d\n", nfsvers, error);
goto keepsearching;
}
+ } else if (nmp->nm_nfs_localport) {
+ strlcpy(((struct sockaddr_un*)&ss)->sun_path, nmp->nm_nfs_localport, sizeof(((struct sockaddr_un*)&ss)->sun_path));
+ NFS_SOCK_DBG("Using supplied nfs_local_port %s for NFS_PROG\n", nmp->nm_nfs_localport);
}
+
/* Create NFS protocol socket and add it to the list of sockets. */
/* N.B. If nfsvers is NFS_VER4 at this point then we're on a non standard port */
+ if (ss.ss_family == AF_LOCAL) {
+ NFS_SOCK_DBG("Creating NFS socket for %s port = %d\n", ((struct sockaddr_un*)&ss)->sun_path, port);
+ }
error = nfs_socket_create(nmp, (struct sockaddr*)&ss, nso->nso_sotype, port,
NFS_PROG, nfsvers, NMFLAG(nmp, RESVPORT), &nsonfs);
if (error) {
nfs_socket_search_update_error(&nss, error);
nfs_socket_destroy(nso);
+ NFS_SOCK_DBG("Could not create NFS socket: %d\n", error);
goto keepsearching;
}
nsonfs->nso_location = nso->nso_location;
nfs_socket_search_update_error(&nss, error);
nfs_socket_destroy(nsonfs);
nfs_socket_destroy(nso);
+ NFS_SOCK_DBG("Could not nfs_connect_upcall: %d", error);
goto keepsearching;
}
TAILQ_INSERT_TAIL(&nss.nss_socklist, nsonfs, nso_link);
error = 0;
bcopy(nso->nso_saddr, &ss, nso->nso_saddr->sa_len);
port = nmp->nm_mountport;
+ NFS_SOCK_DBG("mount port = %d\n", port);
if (ss.ss_family == AF_INET) {
((struct sockaddr_in*)&ss)->sin_port = htons(port);
} else if (ss.ss_family == AF_INET6) {
((struct sockaddr_in6*)&ss)->sin6_port = htons(port);
+ } else if (ss.ss_family == AF_LOCAL && nmp->nm_mount_localport) {
+ NFS_SOCK_DBG("Setting mount address to %s port = %d\n", nmp->nm_mount_localport, nmp->nm_mountport);
+ strlcpy(((struct sockaddr_un*)&ss)->sun_path, nmp->nm_mount_localport, sizeof(((struct sockaddr_un*)&ss)->sun_path));
}
if (!port) {
/* Get port/sockaddr for MOUNT version corresponding to NFS version. */
/* If NFS version is unknown, optimistically choose for NFSv3. */
int mntvers = (nfsvers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
int mntproto = (NM_OMFLAG(nmp, MNTUDP) || (nso->nso_sotype == SOCK_DGRAM)) ? IPPROTO_UDP : IPPROTO_TCP;
+ NFS_SOCK_DBG("Looking up mount port with socket %p\n", nso->nso_so);
error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
- nso->nso_so, RPCPROG_MNT, mntvers, mntproto, timeo);
+ nso->nso_so, RPCPROG_MNT, mntvers, mntproto == IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM, timeo);
}
if (!error) {
if (ss.ss_family == AF_INET) {
port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
} else if (ss.ss_family == AF_INET6) {
port = ntohs(((struct sockaddr_in6*)&ss)->sin6_port);
+ } else if (ss.ss_family == AF_LOCAL) {
+ port = (((struct sockaddr_un*)&ss)->sun_path[0] != '\0');
}
if (!port) {
error = EPROGUNAVAIL;
bcopy(&ss, nsonfs->nso_saddr2, ss.ss_len);
}
if (error) {
+ NFS_SOCK_DBG("Could not create mount sockaet address %d", error);
lck_mtx_lock(&nsonfs->nso_lock);
nsonfs->nso_error = error;
nsonfs->nso_flags |= NSO_DEAD;
lck_mtx_unlock(&nsonfs->nso_lock);
}
}
+ NFS_SOCK_DBG("Destroying socket %p so %p\n", nso, nso->nso_so);
nfs_socket_destroy(nso);
goto keepsearching;
}
saddr = nso->nso_saddr2;
if (!saddr) {
/* Need sockaddr for MOUNT port */
+ NFS_SOCK_DBG("Getting mount address mountport = %d, mount_localport = %s\n", nmp->nm_mountport, nmp->nm_mount_localport);
bcopy(nso->nso_saddr, &ss, nso->nso_saddr->sa_len);
port = nmp->nm_mountport;
if (ss.ss_family == AF_INET) {
((struct sockaddr_in*)&ss)->sin_port = htons(port);
} else if (ss.ss_family == AF_INET6) {
((struct sockaddr_in6*)&ss)->sin6_port = htons(port);
+ } else if (ss.ss_family == AF_LOCAL && nmp->nm_mount_localport) {
+ NFS_SOCK_DBG("Setting mount address to %s port = %d\n", nmp->nm_mount_localport, nmp->nm_mountport);
+ strlcpy(((struct sockaddr_un*)&ss)->sun_path, nmp->nm_mount_localport, sizeof(((struct sockaddr_un*)&ss)->sun_path));
}
if (!port) {
/* Get port/sockaddr for MOUNT version corresponding to NFS version. */
int mntvers = (nfsvers == NFS_VER2) ? RPCMNT_VER1 : RPCMNT_VER3;
- int mntproto = (NM_OMFLAG(nmp, MNTUDP) || (nso->nso_sotype == SOCK_DGRAM)) ? IPPROTO_UDP : IPPROTO_TCP;
+ int so_type = NM_OMFLAG(nmp, MNTUDP) ? SOCK_DGRAM : nso->nso_sotype;
error = nfs_portmap_lookup(nmp, vfs_context_current(), (struct sockaddr*)&ss,
- NULL, RPCPROG_MNT, mntvers, mntproto, timeo);
+ NULL, RPCPROG_MNT, mntvers, so_type, timeo);
if (ss.ss_family == AF_INET) {
port = ntohs(((struct sockaddr_in*)&ss)->sin_port);
} else if (ss.ss_family == AF_INET6) {
}
if (!nmp->nm_vers) {
nmp->nm_vers = nfsvers;
+#if CONFIG_NFS4
/* If we negotiated NFSv4, set nm_nfsport if we ended up on the standard NFS port */
if ((nfsvers >= NFS_VER4) && !NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_PORT)) {
if (nso->nso_saddr->sa_family == AF_INET) {
nmp->nm_nfsport = NFS_PORT;
}
}
+#endif
}
+#if CONFIG_NFS4
/* do some version-specific pre-mount set up */
if (nmp->nm_vers >= NFS_VER4) {
microtime(&now);
nfs4_mount_callback_setup(nmp);
}
}
+#endif
}
/* Initialize NFS socket state variables */
nmp->nm_sotype = 0;
}
if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_VERSION)) {
+#if CONFIG_NFS4
if (nmp->nm_vers >= NFS_VER4) {
if (!NFS_BITMAP_ISSET(nmp->nm_mattrs, NFS_MATTR_NFS_PORT)) {
nmp->nm_nfsport = 0;
}
bzero(&nmp->nm_un, sizeof(nmp->nm_un));
}
+#endif
nmp->nm_vers = 0;
}
}
/* setup & confirm socket connection is functional */
int
-nfs_connect_setup(struct nfsmount *nmp)
+nfs_connect_setup(
+#if !CONFIG_NFS4
+ __unused
+#endif
+ struct nfsmount *nmp)
{
int error = 0;
-
+#if CONFIG_NFS4
if (nmp->nm_vers >= NFS_VER4) {
if (nmp->nm_state & NFSSTA_CLIENTID) {
/* first, try to renew our current state */
}
error = nfs4_setclientid(nmp);
}
+#endif
return error;
}
lck_mtx_lock(&nmp->nm_lock);
tryagain:
if (nmp->nm_nso) {
- struct timespec ts = { 1, 0 };
+ struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
if (nmp->nm_state & NFSSTA_SENDING) { /* wait for sending to complete */
nmp->nm_state |= NFSSTA_WANTSND;
msleep(&nmp->nm_state, &nmp->nm_lock, PZERO - 1, "nfswaitsending", &ts);
nfs_mount_sock_thread(void *arg, __unused wait_result_t wr)
{
struct nfsmount *nmp = arg;
- struct timespec ts = { 30, 0 };
+ struct timespec ts = { .tv_sec = 30, .tv_nsec = 0 };
thread_t thd = current_thread();
struct nfsreq *req;
struct timeval now;
if (error == EIO || error == EINTR) {
lvl = (do_reconnect_sleep++ % 600) ? 7 : 0;
}
- nfs_printf(NFS_FAC_SOCK, lvl, "nfs reconnect %s: returned %d\n",
+ NFS_DBG(NFS_FAC_SOCK, lvl, "nfs reconnect %s: returned %d\n",
vfs_statfs(nmp->nm_mountp)->f_mntfromname, error);
} else {
nmp->nm_reconnect_start = 0;
nfs_recover(nmp);
lck_mtx_lock(&nmp->nm_lock);
}
+#if CONFIG_NFS4
/* handle NFSv4 delegation returns */
while ((nmp->nm_vers >= NFS_VER4) && !(nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD)) &&
(nmp->nm_sockflags & NMSOCK_READY) && !(nmp->nm_state & NFSSTA_RECOVER) &&
nfs4_delegation_return(np, R_RECOVER, thd, nmp->nm_mcred);
lck_mtx_lock(&nmp->nm_lock);
}
+#endif
/* do resends, if necessary/possible */
while ((((nmp->nm_sockflags & NMSOCK_READY) && !(nmp->nm_state & NFSSTA_RECOVER)) ||
(nmp->nm_state & (NFSSTA_FORCE | NFSSTA_DEAD))) &&
lck_mtx_unlock(&req->r_mtx);
/* async RPCs on GSS mounts need to be rebuilt and resent. */
nfs_reqdequeue(req);
+#if CONFIG_NFS_GSS
if (nfs_request_using_gss(req)) {
nfs_gss_clnt_rpcdone(req);
error = nfs_gss_clnt_args_restore(req);
req->r_xid = 0;
}
}
+#endif /* CONFIG_NFS_GSS */
NFS_SOCK_DBG("nfs async%s restart: p %d x 0x%llx f 0x%x rtt %d\n",
nfs_request_using_gss(req) ? " gss" : "", req->r_procnum, req->r_xid,
req->r_flags, req->r_rtt);
#define NCBSOCK_UPCALLWANT 0x0002
#define NCBSOCK_DEAD 0x0004
+#if CONFIG_NFS4
/*
* NFS callback channel state
*
struct nfs_callback_socket *ncbsp;
socket_t so, so6;
struct nfs4_cb_sock_list cb_socks;
- struct timespec ts = {1, 0};
+ struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
lck_mtx_lock(nfs_global_mutex);
TAILQ_REMOVE(&nfs4_cb_mounts, nmp, nm_cblink);
nfs4_cb_rcv(socket_t so, void *arg, __unused int waitflag)
{
struct nfs_callback_socket *ncbsp = arg;
- struct timespec ts = {1, 0};
+ struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 };
struct timeval now;
mbuf_t m;
int error = 0, recv = 1;
}
return error;
}
-
+#endif /* CONFIG_NFS4 */
/*
* Initialize an nfs_rpc_record_state structure.
struct sockaddr *sendnam;
mbuf_t mreqcopy;
size_t sentlen = 0;
- struct timespec ts = { 2, 0 };
+ struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
again:
error = nfs_sndlock(req);
msg.msg_name = (caddr_t)sendnam;
msg.msg_namelen = sendnam->sa_len;
}
+ NFS_SOCK_DUMP_MBUF("Sending mbuf\n", mreqcopy);
error = sock_sendmbuf(nso->nso_so, &msg, mreqcopy, 0, &sentlen);
if (error || (sentlen != req->r_mreqlen)) {
NFS_SOCK_DBG("nfs_send: 0x%llx sent %d/%d error %d\n",
/* signal anyone waiting on this request */
wakeup(req);
asyncioq = (req->r_callback.rcb_func != NULL);
+#if CONFIG_NFS_GSS
if (nfs_request_using_gss(req)) {
nfs_gss_clnt_rpcdone(req);
}
+#endif /* CONFIG_NFS_GSS */
lck_mtx_unlock(&req->r_mtx);
lck_mtx_unlock(nfs_request_mutex);
/* if it's an async RPC with a callback, queue it up */
int
nfs_wait_reply(struct nfsreq *req)
{
- struct timespec ts = { 2, 0 };
+ struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
int error = 0, slpflag, first = 1;
if (req->r_nmp && NMFLAG(req->r_nmp, INTR) && req->r_thread && !(req->r_flags & R_NOINTR)) {
nfs_request_destroy(struct nfsreq *req)
{
struct nfsmount *nmp;
- struct gss_seq *gsp, *ngsp;
int clearjbtimeo = 0;
+#if CONFIG_NFS_GSS
+ struct gss_seq *gsp, *ngsp;
+#endif
+
if (!req || !(req->r_flags & R_INITTED)) {
return;
}
if (IS_VALID_CRED(req->r_cred)) {
kauth_cred_unref(&req->r_cred);
}
+#if CONFIG_NFS_GSS
if (nfs_request_using_gss(req)) {
nfs_gss_clnt_rpcdone(req);
}
if (req->r_gss_ctx) {
nfs_gss_clnt_ctx_unref(req);
}
+#endif /* CONFIG_NFS_GSS */
if (req->r_wrongsec) {
FREE(req->r_wrongsec, M_TEMP);
}
lck_mtx_unlock(&nmp->nm_lock);
}
+#if CONFIG_NFS_GSS
if (nfs_request_using_gss(req)) {
/*
* If the request used an RPCSEC_GSS credential
goto nfsmout;
}
}
+#endif /* CONFIG_NFS_GSS */
/*
* If there was a successful reply, make sure to mark the mount as up.
nfsm_chain_get_32(error, &nmrep, auth_status);
nfsmout_if(error);
switch (auth_status) {
+#if CONFIG_NFS_GSS
case RPCSEC_GSS_CREDPROBLEM:
case RPCSEC_GSS_CTXPROBLEM:
/*
req->r_xid = 0; // get a new XID
req->r_flags |= R_RESTART;
goto nfsmout;
+#endif /* CONFIG_NFS_GSS */
default:
error = EACCES;
break;
}
nfsm_chain_get_32(error, &nmrep, accepted_status);
break;
+#if CONFIG_NFS_GSS
case RPCAUTH_KRB5:
case RPCAUTH_KRB5I:
case RPCAUTH_KRB5P:
error = nfs_gss_clnt_verf_get(req, &nmrep,
verf_type, verf_len, &accepted_status);
break;
+#endif /* CONFIG_NFS_GSS */
}
nfsmout_if(error);
nfs_up(nmp, req->r_thread, clearjbtimeo, "resource available again");
}
+#if CONFIG_NFS4
if ((nmp->nm_vers >= NFS_VER4) && (*status == NFSERR_WRONGSEC)) {
/*
* Hmmm... we need to try a different security flavor.
req->r_np->n_auth = req->r_auth;
}
}
-
+#endif /* CONFIG_NFS4 */
if (*status == NFS_OK) {
/*
* Successful NFS request
}
+#if CONFIG_NFS_GSS
/*
* Set up a new null proc request to exchange GSS context tokens with the
* server. Associate the context that we are setting up with the request that we
return error;
}
+#endif /* CONFIG_NFS_GSS */
/*
* Create and start an asynchronous NFS request.
if (!error && !(req->r_flags & R_SENT) && req->r_callback.rcb_func) {
/* make sure to wait until this async I/O request gets sent */
int slpflag = (req->r_nmp && NMFLAG(req->r_nmp, INTR) && req->r_thread && !(req->r_flags & R_NOINTR)) ? PCATCH : 0;
- struct timespec ts = { 2, 0 };
+ struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
while (!(req->r_flags & R_SENT)) {
nmp = req->r_nmp;
if ((req->r_flags & R_RESENDQ) && !nfs_mount_gone(nmp)) {
req->r_flags |= R_ASYNCWAIT;
}
while (req->r_flags & R_RESENDQ) { /* wait until the request is off the resend queue */
- struct timespec ts = { 2, 0 };
+ struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 };
if ((nmp = req->r_nmp)) {
lck_mtx_lock(&nmp->nm_lock);
struct nfsmount *nmp = req->r_nmp;
int *statep;
int error = 0, slpflag = 0;
- struct timespec ts = { 0, 0 };
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
if (nfs_mount_gone(nmp)) {
return ENXIO;
int error = 0, on = 1, try, sendat = 2, soproto, recv, optlen, restoreto = 0;
socket_t newso = NULL;
struct sockaddr_storage ss;
- struct timeval orig_rcvto, orig_sndto, tv = { 1, 0 };
+ struct timeval orig_rcvto, orig_sndto, tv = { .tv_sec = 1, .tv_usec = 0 };
mbuf_t m, mrep = NULL;
struct msghdr msg;
uint32_t rxid = 0, reply = 0, reply_status, rejected_status;
if (!so) {
/* create socket and set options */
- soproto = (sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP;
+ if (saddr->sa_family == AF_LOCAL) {
+ soproto = 0;
+ } else {
+ soproto = (sotype == SOCK_DGRAM) ? IPPROTO_UDP : IPPROTO_TCP;
+ }
if ((error = sock_socket(saddr->sa_family, sotype, soproto, NULL, NULL, &newso))) {
goto nfsmout;
}
- if (bindresv) {
+ if (bindresv && saddr->sa_family != AF_LOCAL) {
int level = (saddr->sa_family == AF_INET) ? IPPROTO_IP : IPPROTO_IPV6;
int optname = (saddr->sa_family == AF_INET) ? IP_PORTRANGE : IPV6_PORTRANGE;
int portrange = IP_PORTRANGE_LOW;
socket_t so,
uint32_t protocol,
uint32_t vers,
- uint32_t ipproto,
+ uint32_t stype,
int timeo)
{
thread_t thd = vfs_context_thread(ctx);
kauth_cred_t cred = vfs_context_ucred(ctx);
struct sockaddr_storage ss;
struct sockaddr *saddr = (struct sockaddr*)&ss;
+ static struct sockaddr_un rpcbind_cots = {
+ sizeof(struct sockaddr_un),
+ AF_LOCAL,
+ RPCB_TICOTSORD_PATH
+ };
+ static struct sockaddr_un rpcbind_clts = {
+ sizeof(struct sockaddr_un),
+ AF_LOCAL,
+ RPCB_TICLTS_PATH
+ };
struct nfsm_chain nmreq, nmrep;
mbuf_t mreq;
int error = 0, ip, pmprog, pmvers, pmproc;
pmprog = RPCBPROG;
pmvers = RPCBVERS4;
pmproc = RPCBPROC_GETVERSADDR;
+ } else if (saddr->sa_family == AF_LOCAL) {
+ ip = 0;
+ pmprog = RPCBPROG;
+ pmvers = RPCBVERS4;
+ pmproc = RPCBPROC_GETVERSADDR;
+ NFS_SOCK_DBG("%s\n", ((struct sockaddr_un*)sa)->sun_path);
+ saddr = (struct sockaddr*)((stype == SOCK_STREAM) ? &rpcbind_cots : &rpcbind_clts);
} else {
return EINVAL;
}
/* send portmapper request to get port/uaddr */
if (ip == 4) {
((struct sockaddr_in*)saddr)->sin_port = htons(PMAPPORT);
- } else {
+ } else if (ip == 6) {
((struct sockaddr_in6*)saddr)->sin6_port = htons(PMAPPORT);
}
nfsm_chain_build_alloc_init(error, &nmreq, 8 * NFSX_UNSIGNED);
nfsm_chain_add_32(error, &nmreq, protocol);
nfsm_chain_add_32(error, &nmreq, vers);
if (ip == 4) {
- nfsm_chain_add_32(error, &nmreq, ipproto);
+ nfsm_chain_add_32(error, &nmreq, stype == SOCK_STREAM ? IPPROTO_TCP : IPPROTO_UDP);
nfsm_chain_add_32(error, &nmreq, 0);
} else {
- if (ipproto == IPPROTO_TCP) {
- nfsm_chain_add_string(error, &nmreq, "tcp6", 4);
+ if (stype == SOCK_STREAM) {
+ if (ip == 6) {
+ nfsm_chain_add_string(error, &nmreq, "tcp6", 4);
+ } else {
+ nfsm_chain_add_string(error, &nmreq, "ticotsord", 9);
+ }
} else {
- nfsm_chain_add_string(error, &nmreq, "udp6", 4);
+ if (ip == 6) {
+ nfsm_chain_add_string(error, &nmreq, "udp6", 4);
+ } else {
+ nfsm_chain_add_string(error, &nmreq, "ticlts", 6);
+ }
}
nfsm_chain_add_string(error, &nmreq, "", 0); /* uaddr */
nfsm_chain_add_string(error, &nmreq, "", 0); /* owner */
}
nfsm_chain_build_done(error, &nmreq);
nfsmout_if(error);
- error = nfsm_rpchead2(nmp, (ipproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
- pmprog, pmvers, pmproc, RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead,
- &xid, &mreq);
+ error = nfsm_rpchead2(nmp, stype, pmprog, pmvers, pmproc,
+ RPCAUTH_SYS, cred, NULL, nmreq.nmc_mhead, &xid, &mreq);
nfsmout_if(error);
nmreq.nmc_mhead = NULL;
- error = nfs_aux_request(nmp, thd, saddr, so, (ipproto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM,
- mreq, R_XID32(xid), 0, timeo, &nmrep);
+
+ NFS_SOCK_DUMP_MBUF("nfs_portmap_loockup request", mreq);
+ error = nfs_aux_request(nmp, thd, saddr, so,
+ stype, mreq, R_XID32(xid), 0, timeo, &nmrep);
+ NFS_SOCK_DUMP_MBUF("nfs_portmap_lookup reply", nmrep.nmc_mhead);
+ NFS_SOCK_DBG("rpcbind request returned %d for program %u vers %u: %s\n", error, protocol, vers,
+ (saddr->sa_family == AF_LOCAL) ? ((struct sockaddr_un *)saddr)->sun_path :
+ (saddr->sa_family == AF_INET6) ? "INET6 socket" : "INET socket");
/* grab port from portmap response */
if (ip == 4) {
if (ualen < 1) {
/* program is not available, just return a zero port */
bcopy(sa, saddr, min(sizeof(ss), sa->sa_len));
- ((struct sockaddr_in6*)saddr)->sin6_port = htons(0);
+ if (ip == 6) {
+ ((struct sockaddr_in6*)saddr)->sin6_port = htons(0);
+ } else {
+ ((struct sockaddr_un*)saddr)->sun_path[0] = '\0';
+ }
+ NFS_SOCK_DBG("Program %u version %u unavailable", protocol, vers);
} else {
nfsm_chain_get_opaque(error, &nmrep, ualen, uaddr);
+ NFS_SOCK_DBG("Got uaddr %s\n", uaddr);
if (!error) {
uaddr[ualen] = '\0';
if (!nfs_uaddr2sockaddr(uaddr, saddr)) {
nfsmout:
nfsm_chain_cleanup(&nmreq);
nfsm_chain_cleanup(&nmrep);
+ NFS_SOCK_DBG("Returned %d\n", error);
+
return error;
}
msg.msg_namelen = sendnam->sa_len;
}
}
+ if (NFS_IS_DBG(NFS_FAC_SRV, 15)) {
+ nfs_dump_mbuf(__func__, __LINE__, "nfsrv_send\n", top);
+ }
error = sock_sendmbuf(so, &msg, top, 0, NULL);
if (!error) {
return 0;