/** * probe_bothports - discover the RPC endpoints of mountd and NFS server * @mnt_server: pointer to address and pmap argument for mountd results * @nfs_server: pointer to address and pmap argument for NFS server * * This is the legacy API that takes "clnt_addr_t" for both servers, * but supports only AF_INET addresses. * * Returns 1 and fills in the pmap field in both clnt_addr_t structs * if the requested service ports are unambiguous and pingable. * Otherwise zero is returned; rpccreateerr.cf_stat is set to reflect * the nature of the error. */ int probe_bothports(clnt_addr_t *mnt_server, clnt_addr_t *nfs_server) { return nfs_probe_bothports((struct sockaddr *)&mnt_server->saddr, sizeof(mnt_server->saddr), &mnt_server->pmap, (struct sockaddr *)&nfs_server->saddr, sizeof(nfs_server->saddr), &nfs_server->pmap); }
/* * Reconstruct the mount option string based on a portmapper probe * of the server. Returns one if the server's portmapper returned * something we can use, otherwise zero. * * To handle version and transport protocol fallback properly, we * need to parse some of the mount options in order to set up a * portmap probe. Mount options that nfs_rewrite_pmap_mount_options() * doesn't recognize are left alone. * * Returns TRUE if rewriting was successful; otherwise * FALSE is returned if some failure occurred. */ static int nfs_rewrite_pmap_mount_options(struct mount_options *options, int checkv4, struct local_bind_info *local_ip) { union nfs_sockaddr nfs_address; struct sockaddr *nfs_saddr = &nfs_address.sa; socklen_t nfs_salen = sizeof(nfs_address); struct pmap nfs_pmap; union nfs_sockaddr mnt_address; struct sockaddr *mnt_saddr = &mnt_address.sa; socklen_t mnt_salen = sizeof(mnt_address); unsigned long protocol; struct pmap mnt_pmap; /* * Version and transport negotiation is not required * and does not work for RDMA mounts. */ if (!nfs_nfs_protocol(options, &protocol)) { errno = EINVAL; return 0; } if (protocol == NFSPROTO_RDMA) goto out; /* * Extract just the options needed to contact server. * Bail now if any of these have bad values. */ if (!nfs_extract_server_addresses(options, nfs_saddr, &nfs_salen, mnt_saddr, &mnt_salen)) { errno = EINVAL; return 0; } if (!nfs_options2pmap(options, &nfs_pmap, &mnt_pmap)) { errno = EINVAL; return 0; } /* * The kernel NFS client doesn't support changing the RPC * program number for these services, so force the value of * these fields before probing the server's ports. */ nfs_pmap.pm_prog = NFS_PROGRAM; mnt_pmap.pm_prog = MOUNTPROG; /* * If the server's rpcbind service isn't available, we can't * negotiate. Bail now if we can't contact it. */ if (!nfs_probe_bothports(mnt_saddr, mnt_salen, &mnt_pmap, nfs_saddr, nfs_salen, &nfs_pmap, checkv4, local_ip)) { errno = ESPIPE; if (rpc_createerr.cf_stat == RPC_PROGNOTREGISTERED) errno = EOPNOTSUPP; else if (rpc_createerr.cf_stat == RPC_AUTHERROR) errno = EACCES; else if (rpc_createerr.cf_stat == RPC_TIMEDOUT) errno = ETIMEDOUT; else if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH) errno = EPROTONOSUPPORT; else if (rpc_createerr.cf_error.re_errno != 0) errno = rpc_createerr.cf_error.re_errno; return 0; } if (!nfs_construct_new_options(options, nfs_saddr, &nfs_pmap, mnt_saddr, &mnt_pmap)) { if (rpc_createerr.cf_stat == RPC_UNKNOWNPROTO) errno = EPROTONOSUPPORT; else errno = EINVAL; return 0; } out: errno = 0; return 1; }