162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * In-kernel MOUNT protocol client 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/types.h> 962306a36Sopenharmony_ci#include <linux/socket.h> 1062306a36Sopenharmony_ci#include <linux/kernel.h> 1162306a36Sopenharmony_ci#include <linux/errno.h> 1262306a36Sopenharmony_ci#include <linux/uio.h> 1362306a36Sopenharmony_ci#include <linux/net.h> 1462306a36Sopenharmony_ci#include <linux/in.h> 1562306a36Sopenharmony_ci#include <linux/sunrpc/clnt.h> 1662306a36Sopenharmony_ci#include <linux/sunrpc/sched.h> 1762306a36Sopenharmony_ci#include <linux/nfs_fs.h> 1862306a36Sopenharmony_ci#include "internal.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define NFSDBG_FACILITY NFSDBG_MOUNT 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* 2362306a36Sopenharmony_ci * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci#define MNTPATHLEN (1024) 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * XDR data type sizes 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_ci#define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN)) 3162306a36Sopenharmony_ci#define MNT_status_sz (1) 3262306a36Sopenharmony_ci#define MNT_fhandle_sz XDR_QUADLEN(NFS2_FHSIZE) 3362306a36Sopenharmony_ci#define MNT_fhandlev3_sz XDR_QUADLEN(NFS3_FHSIZE) 3462306a36Sopenharmony_ci#define MNT_authflav3_sz (1 + NFS_MAX_SECFLAVORS) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* 3762306a36Sopenharmony_ci * XDR argument and result sizes 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci#define MNT_enc_dirpath_sz encode_dirpath_sz 4062306a36Sopenharmony_ci#define MNT_dec_mountres_sz (MNT_status_sz + MNT_fhandle_sz) 4162306a36Sopenharmony_ci#define MNT_dec_mountres3_sz (MNT_status_sz + MNT_fhandlev3_sz + \ 4262306a36Sopenharmony_ci MNT_authflav3_sz) 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* 4562306a36Sopenharmony_ci * Defined by RFC 1094, section A.5 4662306a36Sopenharmony_ci */ 4762306a36Sopenharmony_cienum { 4862306a36Sopenharmony_ci MOUNTPROC_NULL = 0, 4962306a36Sopenharmony_ci MOUNTPROC_MNT = 1, 5062306a36Sopenharmony_ci MOUNTPROC_DUMP = 2, 5162306a36Sopenharmony_ci MOUNTPROC_UMNT = 3, 5262306a36Sopenharmony_ci MOUNTPROC_UMNTALL = 4, 5362306a36Sopenharmony_ci MOUNTPROC_EXPORT = 5, 5462306a36Sopenharmony_ci}; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci/* 5762306a36Sopenharmony_ci * Defined by RFC 1813, section 5.2 5862306a36Sopenharmony_ci */ 5962306a36Sopenharmony_cienum { 6062306a36Sopenharmony_ci MOUNTPROC3_NULL = 0, 6162306a36Sopenharmony_ci MOUNTPROC3_MNT = 1, 6262306a36Sopenharmony_ci MOUNTPROC3_DUMP = 2, 6362306a36Sopenharmony_ci MOUNTPROC3_UMNT = 3, 6462306a36Sopenharmony_ci MOUNTPROC3_UMNTALL = 4, 6562306a36Sopenharmony_ci MOUNTPROC3_EXPORT = 5, 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic const struct rpc_program mnt_program; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * Defined by OpenGroup XNFS Version 3W, chapter 8 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cienum mountstat { 7462306a36Sopenharmony_ci MNT_OK = 0, 7562306a36Sopenharmony_ci MNT_EPERM = 1, 7662306a36Sopenharmony_ci MNT_ENOENT = 2, 7762306a36Sopenharmony_ci MNT_EACCES = 13, 7862306a36Sopenharmony_ci MNT_EINVAL = 22, 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistatic struct { 8262306a36Sopenharmony_ci u32 status; 8362306a36Sopenharmony_ci int errno; 8462306a36Sopenharmony_ci} mnt_errtbl[] = { 8562306a36Sopenharmony_ci { .status = MNT_OK, .errno = 0, }, 8662306a36Sopenharmony_ci { .status = MNT_EPERM, .errno = -EPERM, }, 8762306a36Sopenharmony_ci { .status = MNT_ENOENT, .errno = -ENOENT, }, 8862306a36Sopenharmony_ci { .status = MNT_EACCES, .errno = -EACCES, }, 8962306a36Sopenharmony_ci { .status = MNT_EINVAL, .errno = -EINVAL, }, 9062306a36Sopenharmony_ci}; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * Defined by RFC 1813, section 5.1.5 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_cienum mountstat3 { 9662306a36Sopenharmony_ci MNT3_OK = 0, /* no error */ 9762306a36Sopenharmony_ci MNT3ERR_PERM = 1, /* Not owner */ 9862306a36Sopenharmony_ci MNT3ERR_NOENT = 2, /* No such file or directory */ 9962306a36Sopenharmony_ci MNT3ERR_IO = 5, /* I/O error */ 10062306a36Sopenharmony_ci MNT3ERR_ACCES = 13, /* Permission denied */ 10162306a36Sopenharmony_ci MNT3ERR_NOTDIR = 20, /* Not a directory */ 10262306a36Sopenharmony_ci MNT3ERR_INVAL = 22, /* Invalid argument */ 10362306a36Sopenharmony_ci MNT3ERR_NAMETOOLONG = 63, /* Filename too long */ 10462306a36Sopenharmony_ci MNT3ERR_NOTSUPP = 10004, /* Operation not supported */ 10562306a36Sopenharmony_ci MNT3ERR_SERVERFAULT = 10006, /* A failure on the server */ 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic struct { 10962306a36Sopenharmony_ci u32 status; 11062306a36Sopenharmony_ci int errno; 11162306a36Sopenharmony_ci} mnt3_errtbl[] = { 11262306a36Sopenharmony_ci { .status = MNT3_OK, .errno = 0, }, 11362306a36Sopenharmony_ci { .status = MNT3ERR_PERM, .errno = -EPERM, }, 11462306a36Sopenharmony_ci { .status = MNT3ERR_NOENT, .errno = -ENOENT, }, 11562306a36Sopenharmony_ci { .status = MNT3ERR_IO, .errno = -EIO, }, 11662306a36Sopenharmony_ci { .status = MNT3ERR_ACCES, .errno = -EACCES, }, 11762306a36Sopenharmony_ci { .status = MNT3ERR_NOTDIR, .errno = -ENOTDIR, }, 11862306a36Sopenharmony_ci { .status = MNT3ERR_INVAL, .errno = -EINVAL, }, 11962306a36Sopenharmony_ci { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, }, 12062306a36Sopenharmony_ci { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, }, 12162306a36Sopenharmony_ci { .status = MNT3ERR_SERVERFAULT, .errno = -EREMOTEIO, }, 12262306a36Sopenharmony_ci}; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistruct mountres { 12562306a36Sopenharmony_ci int errno; 12662306a36Sopenharmony_ci struct nfs_fh *fh; 12762306a36Sopenharmony_ci unsigned int *auth_count; 12862306a36Sopenharmony_ci rpc_authflavor_t *auth_flavors; 12962306a36Sopenharmony_ci}; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistruct mnt_fhstatus { 13262306a36Sopenharmony_ci u32 status; 13362306a36Sopenharmony_ci struct nfs_fh *fh; 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/** 13762306a36Sopenharmony_ci * nfs_mount - Obtain an NFS file handle for the given host and path 13862306a36Sopenharmony_ci * @info: pointer to mount request arguments 13962306a36Sopenharmony_ci * @timeo: deciseconds the mount waits for a response before it retries 14062306a36Sopenharmony_ci * @retrans: number of times the mount retries a request 14162306a36Sopenharmony_ci * 14262306a36Sopenharmony_ci * Uses timeout parameters specified by caller. On successful return, the 14362306a36Sopenharmony_ci * auth_flavs list and auth_flav_len will be populated with the list from the 14462306a36Sopenharmony_ci * server or a faked-up list if the server didn't provide one. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_ciint nfs_mount(struct nfs_mount_request *info, int timeo, int retrans) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct rpc_timeout mnt_timeout; 14962306a36Sopenharmony_ci struct mountres result = { 15062306a36Sopenharmony_ci .fh = info->fh, 15162306a36Sopenharmony_ci .auth_count = info->auth_flav_len, 15262306a36Sopenharmony_ci .auth_flavors = info->auth_flavs, 15362306a36Sopenharmony_ci }; 15462306a36Sopenharmony_ci struct rpc_message msg = { 15562306a36Sopenharmony_ci .rpc_argp = info->dirpath, 15662306a36Sopenharmony_ci .rpc_resp = &result, 15762306a36Sopenharmony_ci }; 15862306a36Sopenharmony_ci struct rpc_create_args args = { 15962306a36Sopenharmony_ci .net = info->net, 16062306a36Sopenharmony_ci .protocol = info->protocol, 16162306a36Sopenharmony_ci .address = (struct sockaddr *)info->sap, 16262306a36Sopenharmony_ci .addrsize = info->salen, 16362306a36Sopenharmony_ci .timeout = &mnt_timeout, 16462306a36Sopenharmony_ci .servername = info->hostname, 16562306a36Sopenharmony_ci .program = &mnt_program, 16662306a36Sopenharmony_ci .version = info->version, 16762306a36Sopenharmony_ci .authflavor = RPC_AUTH_UNIX, 16862306a36Sopenharmony_ci .cred = current_cred(), 16962306a36Sopenharmony_ci }; 17062306a36Sopenharmony_ci struct rpc_clnt *mnt_clnt; 17162306a36Sopenharmony_ci int status; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci dprintk("NFS: sending MNT request for %s:%s\n", 17462306a36Sopenharmony_ci (info->hostname ? info->hostname : "server"), 17562306a36Sopenharmony_ci info->dirpath); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (strlen(info->dirpath) > MNTPATHLEN) 17862306a36Sopenharmony_ci return -ENAMETOOLONG; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci if (info->noresvport) 18162306a36Sopenharmony_ci args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci nfs_init_timeout_values(&mnt_timeout, info->protocol, timeo, retrans); 18462306a36Sopenharmony_ci mnt_clnt = rpc_create(&args); 18562306a36Sopenharmony_ci if (IS_ERR(mnt_clnt)) 18662306a36Sopenharmony_ci goto out_clnt_err; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (info->version == NFS_MNT3_VERSION) 18962306a36Sopenharmony_ci msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; 19062306a36Sopenharmony_ci else 19162306a36Sopenharmony_ci msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT]; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT); 19462306a36Sopenharmony_ci rpc_shutdown_client(mnt_clnt); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci if (status < 0) 19762306a36Sopenharmony_ci goto out_call_err; 19862306a36Sopenharmony_ci if (result.errno != 0) 19962306a36Sopenharmony_ci goto out_mnt_err; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci dprintk("NFS: MNT request succeeded\n"); 20262306a36Sopenharmony_ci status = 0; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* 20562306a36Sopenharmony_ci * If the server didn't provide a flavor list, allow the 20662306a36Sopenharmony_ci * client to try any flavor. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci if (info->version != NFS_MNT3_VERSION || *info->auth_flav_len == 0) { 20962306a36Sopenharmony_ci dprintk("NFS: Faking up auth_flavs list\n"); 21062306a36Sopenharmony_ci info->auth_flavs[0] = RPC_AUTH_NULL; 21162306a36Sopenharmony_ci *info->auth_flav_len = 1; 21262306a36Sopenharmony_ci } 21362306a36Sopenharmony_ciout: 21462306a36Sopenharmony_ci return status; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ciout_clnt_err: 21762306a36Sopenharmony_ci status = PTR_ERR(mnt_clnt); 21862306a36Sopenharmony_ci dprintk("NFS: failed to create MNT RPC client, status=%d\n", status); 21962306a36Sopenharmony_ci goto out; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ciout_call_err: 22262306a36Sopenharmony_ci dprintk("NFS: MNT request failed, status=%d\n", status); 22362306a36Sopenharmony_ci goto out; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ciout_mnt_err: 22662306a36Sopenharmony_ci dprintk("NFS: MNT server returned result %d\n", result.errno); 22762306a36Sopenharmony_ci status = result.errno; 22862306a36Sopenharmony_ci goto out; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci/** 23262306a36Sopenharmony_ci * nfs_umount - Notify a server that we have unmounted this export 23362306a36Sopenharmony_ci * @info: pointer to umount request arguments 23462306a36Sopenharmony_ci * 23562306a36Sopenharmony_ci * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always 23662306a36Sopenharmony_ci * use UDP. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_civoid nfs_umount(const struct nfs_mount_request *info) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci static const struct rpc_timeout nfs_umnt_timeout = { 24162306a36Sopenharmony_ci .to_initval = 1 * HZ, 24262306a36Sopenharmony_ci .to_maxval = 3 * HZ, 24362306a36Sopenharmony_ci .to_retries = 2, 24462306a36Sopenharmony_ci }; 24562306a36Sopenharmony_ci struct rpc_create_args args = { 24662306a36Sopenharmony_ci .net = info->net, 24762306a36Sopenharmony_ci .protocol = IPPROTO_UDP, 24862306a36Sopenharmony_ci .address = (struct sockaddr *)info->sap, 24962306a36Sopenharmony_ci .addrsize = info->salen, 25062306a36Sopenharmony_ci .timeout = &nfs_umnt_timeout, 25162306a36Sopenharmony_ci .servername = info->hostname, 25262306a36Sopenharmony_ci .program = &mnt_program, 25362306a36Sopenharmony_ci .version = info->version, 25462306a36Sopenharmony_ci .authflavor = RPC_AUTH_UNIX, 25562306a36Sopenharmony_ci .flags = RPC_CLNT_CREATE_NOPING, 25662306a36Sopenharmony_ci .cred = current_cred(), 25762306a36Sopenharmony_ci }; 25862306a36Sopenharmony_ci struct rpc_message msg = { 25962306a36Sopenharmony_ci .rpc_argp = info->dirpath, 26062306a36Sopenharmony_ci }; 26162306a36Sopenharmony_ci struct rpc_clnt *clnt; 26262306a36Sopenharmony_ci int status; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (strlen(info->dirpath) > MNTPATHLEN) 26562306a36Sopenharmony_ci return; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci if (info->noresvport) 26862306a36Sopenharmony_ci args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci clnt = rpc_create(&args); 27162306a36Sopenharmony_ci if (IS_ERR(clnt)) 27262306a36Sopenharmony_ci goto out_clnt_err; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci dprintk("NFS: sending UMNT request for %s:%s\n", 27562306a36Sopenharmony_ci (info->hostname ? info->hostname : "server"), info->dirpath); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (info->version == NFS_MNT3_VERSION) 27862306a36Sopenharmony_ci msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT]; 27962306a36Sopenharmony_ci else 28062306a36Sopenharmony_ci msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT]; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci status = rpc_call_sync(clnt, &msg, 0); 28362306a36Sopenharmony_ci rpc_shutdown_client(clnt); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci if (unlikely(status < 0)) 28662306a36Sopenharmony_ci goto out_call_err; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ciout_clnt_err: 29162306a36Sopenharmony_ci dprintk("NFS: failed to create UMNT RPC client, status=%ld\n", 29262306a36Sopenharmony_ci PTR_ERR(clnt)); 29362306a36Sopenharmony_ci return; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ciout_call_err: 29662306a36Sopenharmony_ci dprintk("NFS: UMNT request failed, status=%d\n", status); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* 30062306a36Sopenharmony_ci * XDR encode/decode functions for MOUNT 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic void encode_mntdirpath(struct xdr_stream *xdr, const char *pathname) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci const u32 pathname_len = strlen(pathname); 30662306a36Sopenharmony_ci __be32 *p; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci p = xdr_reserve_space(xdr, 4 + pathname_len); 30962306a36Sopenharmony_ci xdr_encode_opaque(p, pathname, pathname_len); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cistatic void mnt_xdr_enc_dirpath(struct rpc_rqst *req, struct xdr_stream *xdr, 31362306a36Sopenharmony_ci const void *dirpath) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci encode_mntdirpath(xdr, dirpath); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci/* 31962306a36Sopenharmony_ci * RFC 1094: "A non-zero status indicates some sort of error. In this 32062306a36Sopenharmony_ci * case, the status is a UNIX error number." This can be problematic 32162306a36Sopenharmony_ci * if the server and client use different errno values for the same 32262306a36Sopenharmony_ci * error. 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci * However, the OpenGroup XNFS spec provides a simple mapping that is 32562306a36Sopenharmony_ci * independent of local errno values on the server and the client. 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_cistatic int decode_status(struct xdr_stream *xdr, struct mountres *res) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci unsigned int i; 33062306a36Sopenharmony_ci u32 status; 33162306a36Sopenharmony_ci __be32 *p; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 33462306a36Sopenharmony_ci if (unlikely(p == NULL)) 33562306a36Sopenharmony_ci return -EIO; 33662306a36Sopenharmony_ci status = be32_to_cpup(p); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) { 33962306a36Sopenharmony_ci if (mnt_errtbl[i].status == status) { 34062306a36Sopenharmony_ci res->errno = mnt_errtbl[i].errno; 34162306a36Sopenharmony_ci return 0; 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci dprintk("NFS: unrecognized MNT status code: %u\n", status); 34662306a36Sopenharmony_ci res->errno = -EACCES; 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic int decode_fhandle(struct xdr_stream *xdr, struct mountres *res) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct nfs_fh *fh = res->fh; 35362306a36Sopenharmony_ci __be32 *p; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci p = xdr_inline_decode(xdr, NFS2_FHSIZE); 35662306a36Sopenharmony_ci if (unlikely(p == NULL)) 35762306a36Sopenharmony_ci return -EIO; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci fh->size = NFS2_FHSIZE; 36062306a36Sopenharmony_ci memcpy(fh->data, p, NFS2_FHSIZE); 36162306a36Sopenharmony_ci return 0; 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic int mnt_xdr_dec_mountres(struct rpc_rqst *req, 36562306a36Sopenharmony_ci struct xdr_stream *xdr, 36662306a36Sopenharmony_ci void *data) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct mountres *res = data; 36962306a36Sopenharmony_ci int status; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci status = decode_status(xdr, res); 37262306a36Sopenharmony_ci if (unlikely(status != 0 || res->errno != 0)) 37362306a36Sopenharmony_ci return status; 37462306a36Sopenharmony_ci return decode_fhandle(xdr, res); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci unsigned int i; 38062306a36Sopenharmony_ci u32 status; 38162306a36Sopenharmony_ci __be32 *p; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 38462306a36Sopenharmony_ci if (unlikely(p == NULL)) 38562306a36Sopenharmony_ci return -EIO; 38662306a36Sopenharmony_ci status = be32_to_cpup(p); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) { 38962306a36Sopenharmony_ci if (mnt3_errtbl[i].status == status) { 39062306a36Sopenharmony_ci res->errno = mnt3_errtbl[i].errno; 39162306a36Sopenharmony_ci return 0; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci dprintk("NFS: unrecognized MNT3 status code: %u\n", status); 39662306a36Sopenharmony_ci res->errno = -EACCES; 39762306a36Sopenharmony_ci return 0; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_cistatic int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct nfs_fh *fh = res->fh; 40362306a36Sopenharmony_ci u32 size; 40462306a36Sopenharmony_ci __be32 *p; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 40762306a36Sopenharmony_ci if (unlikely(p == NULL)) 40862306a36Sopenharmony_ci return -EIO; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci size = be32_to_cpup(p); 41162306a36Sopenharmony_ci if (size > NFS3_FHSIZE || size == 0) 41262306a36Sopenharmony_ci return -EIO; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci p = xdr_inline_decode(xdr, size); 41562306a36Sopenharmony_ci if (unlikely(p == NULL)) 41662306a36Sopenharmony_ci return -EIO; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci fh->size = size; 41962306a36Sopenharmony_ci memcpy(fh->data, p, size); 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci rpc_authflavor_t *flavors = res->auth_flavors; 42662306a36Sopenharmony_ci unsigned int *count = res->auth_count; 42762306a36Sopenharmony_ci u32 entries, i; 42862306a36Sopenharmony_ci __be32 *p; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci if (*count == 0) 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4); 43462306a36Sopenharmony_ci if (unlikely(p == NULL)) 43562306a36Sopenharmony_ci return -EIO; 43662306a36Sopenharmony_ci entries = be32_to_cpup(p); 43762306a36Sopenharmony_ci dprintk("NFS: received %u auth flavors\n", entries); 43862306a36Sopenharmony_ci if (entries > NFS_MAX_SECFLAVORS) 43962306a36Sopenharmony_ci entries = NFS_MAX_SECFLAVORS; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci p = xdr_inline_decode(xdr, 4 * entries); 44262306a36Sopenharmony_ci if (unlikely(p == NULL)) 44362306a36Sopenharmony_ci return -EIO; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci if (entries > *count) 44662306a36Sopenharmony_ci entries = *count; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci for (i = 0; i < entries; i++) { 44962306a36Sopenharmony_ci flavors[i] = be32_to_cpup(p++); 45062306a36Sopenharmony_ci dprintk("NFS: auth flavor[%u]: %d\n", i, flavors[i]); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci *count = i; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci return 0; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic int mnt_xdr_dec_mountres3(struct rpc_rqst *req, 45862306a36Sopenharmony_ci struct xdr_stream *xdr, 45962306a36Sopenharmony_ci void *data) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct mountres *res = data; 46262306a36Sopenharmony_ci int status; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci status = decode_fhs_status(xdr, res); 46562306a36Sopenharmony_ci if (unlikely(status != 0 || res->errno != 0)) 46662306a36Sopenharmony_ci return status; 46762306a36Sopenharmony_ci status = decode_fhandle3(xdr, res); 46862306a36Sopenharmony_ci if (unlikely(status != 0)) { 46962306a36Sopenharmony_ci res->errno = -EBADHANDLE; 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci return decode_auth_flavors(xdr, res); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic const struct rpc_procinfo mnt_procedures[] = { 47662306a36Sopenharmony_ci [MOUNTPROC_MNT] = { 47762306a36Sopenharmony_ci .p_proc = MOUNTPROC_MNT, 47862306a36Sopenharmony_ci .p_encode = mnt_xdr_enc_dirpath, 47962306a36Sopenharmony_ci .p_decode = mnt_xdr_dec_mountres, 48062306a36Sopenharmony_ci .p_arglen = MNT_enc_dirpath_sz, 48162306a36Sopenharmony_ci .p_replen = MNT_dec_mountres_sz, 48262306a36Sopenharmony_ci .p_statidx = MOUNTPROC_MNT, 48362306a36Sopenharmony_ci .p_name = "MOUNT", 48462306a36Sopenharmony_ci }, 48562306a36Sopenharmony_ci [MOUNTPROC_UMNT] = { 48662306a36Sopenharmony_ci .p_proc = MOUNTPROC_UMNT, 48762306a36Sopenharmony_ci .p_encode = mnt_xdr_enc_dirpath, 48862306a36Sopenharmony_ci .p_arglen = MNT_enc_dirpath_sz, 48962306a36Sopenharmony_ci .p_statidx = MOUNTPROC_UMNT, 49062306a36Sopenharmony_ci .p_name = "UMOUNT", 49162306a36Sopenharmony_ci }, 49262306a36Sopenharmony_ci}; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic const struct rpc_procinfo mnt3_procedures[] = { 49562306a36Sopenharmony_ci [MOUNTPROC3_MNT] = { 49662306a36Sopenharmony_ci .p_proc = MOUNTPROC3_MNT, 49762306a36Sopenharmony_ci .p_encode = mnt_xdr_enc_dirpath, 49862306a36Sopenharmony_ci .p_decode = mnt_xdr_dec_mountres3, 49962306a36Sopenharmony_ci .p_arglen = MNT_enc_dirpath_sz, 50062306a36Sopenharmony_ci .p_replen = MNT_dec_mountres3_sz, 50162306a36Sopenharmony_ci .p_statidx = MOUNTPROC3_MNT, 50262306a36Sopenharmony_ci .p_name = "MOUNT", 50362306a36Sopenharmony_ci }, 50462306a36Sopenharmony_ci [MOUNTPROC3_UMNT] = { 50562306a36Sopenharmony_ci .p_proc = MOUNTPROC3_UMNT, 50662306a36Sopenharmony_ci .p_encode = mnt_xdr_enc_dirpath, 50762306a36Sopenharmony_ci .p_arglen = MNT_enc_dirpath_sz, 50862306a36Sopenharmony_ci .p_statidx = MOUNTPROC3_UMNT, 50962306a36Sopenharmony_ci .p_name = "UMOUNT", 51062306a36Sopenharmony_ci }, 51162306a36Sopenharmony_ci}; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_cistatic unsigned int mnt_counts[ARRAY_SIZE(mnt_procedures)]; 51462306a36Sopenharmony_cistatic const struct rpc_version mnt_version1 = { 51562306a36Sopenharmony_ci .number = 1, 51662306a36Sopenharmony_ci .nrprocs = ARRAY_SIZE(mnt_procedures), 51762306a36Sopenharmony_ci .procs = mnt_procedures, 51862306a36Sopenharmony_ci .counts = mnt_counts, 51962306a36Sopenharmony_ci}; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_cistatic unsigned int mnt3_counts[ARRAY_SIZE(mnt3_procedures)]; 52262306a36Sopenharmony_cistatic const struct rpc_version mnt_version3 = { 52362306a36Sopenharmony_ci .number = 3, 52462306a36Sopenharmony_ci .nrprocs = ARRAY_SIZE(mnt3_procedures), 52562306a36Sopenharmony_ci .procs = mnt3_procedures, 52662306a36Sopenharmony_ci .counts = mnt3_counts, 52762306a36Sopenharmony_ci}; 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic const struct rpc_version *mnt_version[] = { 53062306a36Sopenharmony_ci NULL, 53162306a36Sopenharmony_ci &mnt_version1, 53262306a36Sopenharmony_ci NULL, 53362306a36Sopenharmony_ci &mnt_version3, 53462306a36Sopenharmony_ci}; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic struct rpc_stat mnt_stats; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cistatic const struct rpc_program mnt_program = { 53962306a36Sopenharmony_ci .name = "mount", 54062306a36Sopenharmony_ci .number = NFS_MNT_PROGRAM, 54162306a36Sopenharmony_ci .nrvers = ARRAY_SIZE(mnt_version), 54262306a36Sopenharmony_ci .version = mnt_version, 54362306a36Sopenharmony_ci .stats = &mnt_stats, 54462306a36Sopenharmony_ci}; 545