1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * In-kernel MOUNT protocol client
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de>
6*4882a593Smuzhiyun */
7*4882a593Smuzhiyun
8*4882a593Smuzhiyun #include <linux/types.h>
9*4882a593Smuzhiyun #include <linux/socket.h>
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun #include <linux/uio.h>
13*4882a593Smuzhiyun #include <linux/net.h>
14*4882a593Smuzhiyun #include <linux/in.h>
15*4882a593Smuzhiyun #include <linux/sunrpc/clnt.h>
16*4882a593Smuzhiyun #include <linux/sunrpc/sched.h>
17*4882a593Smuzhiyun #include <linux/nfs_fs.h>
18*4882a593Smuzhiyun #include "internal.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #define NFSDBG_FACILITY NFSDBG_MOUNT
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun * Defined by RFC 1094, section A.3; and RFC 1813, section 5.1.4
24*4882a593Smuzhiyun */
25*4882a593Smuzhiyun #define MNTPATHLEN (1024)
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun /*
28*4882a593Smuzhiyun * XDR data type sizes
29*4882a593Smuzhiyun */
30*4882a593Smuzhiyun #define encode_dirpath_sz (1 + XDR_QUADLEN(MNTPATHLEN))
31*4882a593Smuzhiyun #define MNT_status_sz (1)
32*4882a593Smuzhiyun #define MNT_fhandle_sz XDR_QUADLEN(NFS2_FHSIZE)
33*4882a593Smuzhiyun #define MNT_fhandlev3_sz XDR_QUADLEN(NFS3_FHSIZE)
34*4882a593Smuzhiyun #define MNT_authflav3_sz (1 + NFS_MAX_SECFLAVORS)
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun /*
37*4882a593Smuzhiyun * XDR argument and result sizes
38*4882a593Smuzhiyun */
39*4882a593Smuzhiyun #define MNT_enc_dirpath_sz encode_dirpath_sz
40*4882a593Smuzhiyun #define MNT_dec_mountres_sz (MNT_status_sz + MNT_fhandle_sz)
41*4882a593Smuzhiyun #define MNT_dec_mountres3_sz (MNT_status_sz + MNT_fhandlev3_sz + \
42*4882a593Smuzhiyun MNT_authflav3_sz)
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /*
45*4882a593Smuzhiyun * Defined by RFC 1094, section A.5
46*4882a593Smuzhiyun */
47*4882a593Smuzhiyun enum {
48*4882a593Smuzhiyun MOUNTPROC_NULL = 0,
49*4882a593Smuzhiyun MOUNTPROC_MNT = 1,
50*4882a593Smuzhiyun MOUNTPROC_DUMP = 2,
51*4882a593Smuzhiyun MOUNTPROC_UMNT = 3,
52*4882a593Smuzhiyun MOUNTPROC_UMNTALL = 4,
53*4882a593Smuzhiyun MOUNTPROC_EXPORT = 5,
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /*
57*4882a593Smuzhiyun * Defined by RFC 1813, section 5.2
58*4882a593Smuzhiyun */
59*4882a593Smuzhiyun enum {
60*4882a593Smuzhiyun MOUNTPROC3_NULL = 0,
61*4882a593Smuzhiyun MOUNTPROC3_MNT = 1,
62*4882a593Smuzhiyun MOUNTPROC3_DUMP = 2,
63*4882a593Smuzhiyun MOUNTPROC3_UMNT = 3,
64*4882a593Smuzhiyun MOUNTPROC3_UMNTALL = 4,
65*4882a593Smuzhiyun MOUNTPROC3_EXPORT = 5,
66*4882a593Smuzhiyun };
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun static const struct rpc_program mnt_program;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun /*
71*4882a593Smuzhiyun * Defined by OpenGroup XNFS Version 3W, chapter 8
72*4882a593Smuzhiyun */
73*4882a593Smuzhiyun enum mountstat {
74*4882a593Smuzhiyun MNT_OK = 0,
75*4882a593Smuzhiyun MNT_EPERM = 1,
76*4882a593Smuzhiyun MNT_ENOENT = 2,
77*4882a593Smuzhiyun MNT_EACCES = 13,
78*4882a593Smuzhiyun MNT_EINVAL = 22,
79*4882a593Smuzhiyun };
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun static struct {
82*4882a593Smuzhiyun u32 status;
83*4882a593Smuzhiyun int errno;
84*4882a593Smuzhiyun } mnt_errtbl[] = {
85*4882a593Smuzhiyun { .status = MNT_OK, .errno = 0, },
86*4882a593Smuzhiyun { .status = MNT_EPERM, .errno = -EPERM, },
87*4882a593Smuzhiyun { .status = MNT_ENOENT, .errno = -ENOENT, },
88*4882a593Smuzhiyun { .status = MNT_EACCES, .errno = -EACCES, },
89*4882a593Smuzhiyun { .status = MNT_EINVAL, .errno = -EINVAL, },
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun /*
93*4882a593Smuzhiyun * Defined by RFC 1813, section 5.1.5
94*4882a593Smuzhiyun */
95*4882a593Smuzhiyun enum mountstat3 {
96*4882a593Smuzhiyun MNT3_OK = 0, /* no error */
97*4882a593Smuzhiyun MNT3ERR_PERM = 1, /* Not owner */
98*4882a593Smuzhiyun MNT3ERR_NOENT = 2, /* No such file or directory */
99*4882a593Smuzhiyun MNT3ERR_IO = 5, /* I/O error */
100*4882a593Smuzhiyun MNT3ERR_ACCES = 13, /* Permission denied */
101*4882a593Smuzhiyun MNT3ERR_NOTDIR = 20, /* Not a directory */
102*4882a593Smuzhiyun MNT3ERR_INVAL = 22, /* Invalid argument */
103*4882a593Smuzhiyun MNT3ERR_NAMETOOLONG = 63, /* Filename too long */
104*4882a593Smuzhiyun MNT3ERR_NOTSUPP = 10004, /* Operation not supported */
105*4882a593Smuzhiyun MNT3ERR_SERVERFAULT = 10006, /* A failure on the server */
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun static struct {
109*4882a593Smuzhiyun u32 status;
110*4882a593Smuzhiyun int errno;
111*4882a593Smuzhiyun } mnt3_errtbl[] = {
112*4882a593Smuzhiyun { .status = MNT3_OK, .errno = 0, },
113*4882a593Smuzhiyun { .status = MNT3ERR_PERM, .errno = -EPERM, },
114*4882a593Smuzhiyun { .status = MNT3ERR_NOENT, .errno = -ENOENT, },
115*4882a593Smuzhiyun { .status = MNT3ERR_IO, .errno = -EIO, },
116*4882a593Smuzhiyun { .status = MNT3ERR_ACCES, .errno = -EACCES, },
117*4882a593Smuzhiyun { .status = MNT3ERR_NOTDIR, .errno = -ENOTDIR, },
118*4882a593Smuzhiyun { .status = MNT3ERR_INVAL, .errno = -EINVAL, },
119*4882a593Smuzhiyun { .status = MNT3ERR_NAMETOOLONG, .errno = -ENAMETOOLONG, },
120*4882a593Smuzhiyun { .status = MNT3ERR_NOTSUPP, .errno = -ENOTSUPP, },
121*4882a593Smuzhiyun { .status = MNT3ERR_SERVERFAULT, .errno = -EREMOTEIO, },
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun struct mountres {
125*4882a593Smuzhiyun int errno;
126*4882a593Smuzhiyun struct nfs_fh *fh;
127*4882a593Smuzhiyun unsigned int *auth_count;
128*4882a593Smuzhiyun rpc_authflavor_t *auth_flavors;
129*4882a593Smuzhiyun };
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun struct mnt_fhstatus {
132*4882a593Smuzhiyun u32 status;
133*4882a593Smuzhiyun struct nfs_fh *fh;
134*4882a593Smuzhiyun };
135*4882a593Smuzhiyun
136*4882a593Smuzhiyun /**
137*4882a593Smuzhiyun * nfs_mount - Obtain an NFS file handle for the given host and path
138*4882a593Smuzhiyun * @info: pointer to mount request arguments
139*4882a593Smuzhiyun *
140*4882a593Smuzhiyun * Uses default timeout parameters specified by underlying transport. On
141*4882a593Smuzhiyun * successful return, the auth_flavs list and auth_flav_len will be populated
142*4882a593Smuzhiyun * with the list from the server or a faked-up list if the server didn't
143*4882a593Smuzhiyun * provide one.
144*4882a593Smuzhiyun */
nfs_mount(struct nfs_mount_request * info)145*4882a593Smuzhiyun int nfs_mount(struct nfs_mount_request *info)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun struct mountres result = {
148*4882a593Smuzhiyun .fh = info->fh,
149*4882a593Smuzhiyun .auth_count = info->auth_flav_len,
150*4882a593Smuzhiyun .auth_flavors = info->auth_flavs,
151*4882a593Smuzhiyun };
152*4882a593Smuzhiyun struct rpc_message msg = {
153*4882a593Smuzhiyun .rpc_argp = info->dirpath,
154*4882a593Smuzhiyun .rpc_resp = &result,
155*4882a593Smuzhiyun };
156*4882a593Smuzhiyun struct rpc_create_args args = {
157*4882a593Smuzhiyun .net = info->net,
158*4882a593Smuzhiyun .protocol = info->protocol,
159*4882a593Smuzhiyun .address = info->sap,
160*4882a593Smuzhiyun .addrsize = info->salen,
161*4882a593Smuzhiyun .servername = info->hostname,
162*4882a593Smuzhiyun .program = &mnt_program,
163*4882a593Smuzhiyun .version = info->version,
164*4882a593Smuzhiyun .authflavor = RPC_AUTH_UNIX,
165*4882a593Smuzhiyun .cred = current_cred(),
166*4882a593Smuzhiyun };
167*4882a593Smuzhiyun struct rpc_clnt *mnt_clnt;
168*4882a593Smuzhiyun int status;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun dprintk("NFS: sending MNT request for %s:%s\n",
171*4882a593Smuzhiyun (info->hostname ? info->hostname : "server"),
172*4882a593Smuzhiyun info->dirpath);
173*4882a593Smuzhiyun
174*4882a593Smuzhiyun if (strlen(info->dirpath) > MNTPATHLEN)
175*4882a593Smuzhiyun return -ENAMETOOLONG;
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun if (info->noresvport)
178*4882a593Smuzhiyun args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun mnt_clnt = rpc_create(&args);
181*4882a593Smuzhiyun if (IS_ERR(mnt_clnt))
182*4882a593Smuzhiyun goto out_clnt_err;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun if (info->version == NFS_MNT3_VERSION)
185*4882a593Smuzhiyun msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT];
186*4882a593Smuzhiyun else
187*4882a593Smuzhiyun msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC_MNT];
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun status = rpc_call_sync(mnt_clnt, &msg, RPC_TASK_SOFT|RPC_TASK_TIMEOUT);
190*4882a593Smuzhiyun rpc_shutdown_client(mnt_clnt);
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun if (status < 0)
193*4882a593Smuzhiyun goto out_call_err;
194*4882a593Smuzhiyun if (result.errno != 0)
195*4882a593Smuzhiyun goto out_mnt_err;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun dprintk("NFS: MNT request succeeded\n");
198*4882a593Smuzhiyun status = 0;
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun /*
201*4882a593Smuzhiyun * If the server didn't provide a flavor list, allow the
202*4882a593Smuzhiyun * client to try any flavor.
203*4882a593Smuzhiyun */
204*4882a593Smuzhiyun if (info->version != NFS_MNT3_VERSION || *info->auth_flav_len == 0) {
205*4882a593Smuzhiyun dprintk("NFS: Faking up auth_flavs list\n");
206*4882a593Smuzhiyun info->auth_flavs[0] = RPC_AUTH_NULL;
207*4882a593Smuzhiyun *info->auth_flav_len = 1;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun out:
210*4882a593Smuzhiyun return status;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun out_clnt_err:
213*4882a593Smuzhiyun status = PTR_ERR(mnt_clnt);
214*4882a593Smuzhiyun dprintk("NFS: failed to create MNT RPC client, status=%d\n", status);
215*4882a593Smuzhiyun goto out;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun out_call_err:
218*4882a593Smuzhiyun dprintk("NFS: MNT request failed, status=%d\n", status);
219*4882a593Smuzhiyun goto out;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun out_mnt_err:
222*4882a593Smuzhiyun dprintk("NFS: MNT server returned result %d\n", result.errno);
223*4882a593Smuzhiyun status = result.errno;
224*4882a593Smuzhiyun goto out;
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /**
228*4882a593Smuzhiyun * nfs_umount - Notify a server that we have unmounted this export
229*4882a593Smuzhiyun * @info: pointer to umount request arguments
230*4882a593Smuzhiyun *
231*4882a593Smuzhiyun * MOUNTPROC_UMNT is advisory, so we set a short timeout, and always
232*4882a593Smuzhiyun * use UDP.
233*4882a593Smuzhiyun */
nfs_umount(const struct nfs_mount_request * info)234*4882a593Smuzhiyun void nfs_umount(const struct nfs_mount_request *info)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun static const struct rpc_timeout nfs_umnt_timeout = {
237*4882a593Smuzhiyun .to_initval = 1 * HZ,
238*4882a593Smuzhiyun .to_maxval = 3 * HZ,
239*4882a593Smuzhiyun .to_retries = 2,
240*4882a593Smuzhiyun };
241*4882a593Smuzhiyun struct rpc_create_args args = {
242*4882a593Smuzhiyun .net = info->net,
243*4882a593Smuzhiyun .protocol = IPPROTO_UDP,
244*4882a593Smuzhiyun .address = info->sap,
245*4882a593Smuzhiyun .addrsize = info->salen,
246*4882a593Smuzhiyun .timeout = &nfs_umnt_timeout,
247*4882a593Smuzhiyun .servername = info->hostname,
248*4882a593Smuzhiyun .program = &mnt_program,
249*4882a593Smuzhiyun .version = info->version,
250*4882a593Smuzhiyun .authflavor = RPC_AUTH_UNIX,
251*4882a593Smuzhiyun .flags = RPC_CLNT_CREATE_NOPING,
252*4882a593Smuzhiyun .cred = current_cred(),
253*4882a593Smuzhiyun };
254*4882a593Smuzhiyun struct rpc_message msg = {
255*4882a593Smuzhiyun .rpc_argp = info->dirpath,
256*4882a593Smuzhiyun };
257*4882a593Smuzhiyun struct rpc_clnt *clnt;
258*4882a593Smuzhiyun int status;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun if (strlen(info->dirpath) > MNTPATHLEN)
261*4882a593Smuzhiyun return;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun if (info->noresvport)
264*4882a593Smuzhiyun args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun clnt = rpc_create(&args);
267*4882a593Smuzhiyun if (IS_ERR(clnt))
268*4882a593Smuzhiyun goto out_clnt_err;
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun dprintk("NFS: sending UMNT request for %s:%s\n",
271*4882a593Smuzhiyun (info->hostname ? info->hostname : "server"), info->dirpath);
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun if (info->version == NFS_MNT3_VERSION)
274*4882a593Smuzhiyun msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC3_UMNT];
275*4882a593Smuzhiyun else
276*4882a593Smuzhiyun msg.rpc_proc = &clnt->cl_procinfo[MOUNTPROC_UMNT];
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun status = rpc_call_sync(clnt, &msg, 0);
279*4882a593Smuzhiyun rpc_shutdown_client(clnt);
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun if (unlikely(status < 0))
282*4882a593Smuzhiyun goto out_call_err;
283*4882a593Smuzhiyun
284*4882a593Smuzhiyun return;
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun out_clnt_err:
287*4882a593Smuzhiyun dprintk("NFS: failed to create UMNT RPC client, status=%ld\n",
288*4882a593Smuzhiyun PTR_ERR(clnt));
289*4882a593Smuzhiyun return;
290*4882a593Smuzhiyun
291*4882a593Smuzhiyun out_call_err:
292*4882a593Smuzhiyun dprintk("NFS: UMNT request failed, status=%d\n", status);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun
295*4882a593Smuzhiyun /*
296*4882a593Smuzhiyun * XDR encode/decode functions for MOUNT
297*4882a593Smuzhiyun */
298*4882a593Smuzhiyun
encode_mntdirpath(struct xdr_stream * xdr,const char * pathname)299*4882a593Smuzhiyun static void encode_mntdirpath(struct xdr_stream *xdr, const char *pathname)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun const u32 pathname_len = strlen(pathname);
302*4882a593Smuzhiyun __be32 *p;
303*4882a593Smuzhiyun
304*4882a593Smuzhiyun p = xdr_reserve_space(xdr, 4 + pathname_len);
305*4882a593Smuzhiyun xdr_encode_opaque(p, pathname, pathname_len);
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
mnt_xdr_enc_dirpath(struct rpc_rqst * req,struct xdr_stream * xdr,const void * dirpath)308*4882a593Smuzhiyun static void mnt_xdr_enc_dirpath(struct rpc_rqst *req, struct xdr_stream *xdr,
309*4882a593Smuzhiyun const void *dirpath)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun encode_mntdirpath(xdr, dirpath);
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun /*
315*4882a593Smuzhiyun * RFC 1094: "A non-zero status indicates some sort of error. In this
316*4882a593Smuzhiyun * case, the status is a UNIX error number." This can be problematic
317*4882a593Smuzhiyun * if the server and client use different errno values for the same
318*4882a593Smuzhiyun * error.
319*4882a593Smuzhiyun *
320*4882a593Smuzhiyun * However, the OpenGroup XNFS spec provides a simple mapping that is
321*4882a593Smuzhiyun * independent of local errno values on the server and the client.
322*4882a593Smuzhiyun */
decode_status(struct xdr_stream * xdr,struct mountres * res)323*4882a593Smuzhiyun static int decode_status(struct xdr_stream *xdr, struct mountres *res)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun unsigned int i;
326*4882a593Smuzhiyun u32 status;
327*4882a593Smuzhiyun __be32 *p;
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
330*4882a593Smuzhiyun if (unlikely(p == NULL))
331*4882a593Smuzhiyun return -EIO;
332*4882a593Smuzhiyun status = be32_to_cpup(p);
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(mnt_errtbl); i++) {
335*4882a593Smuzhiyun if (mnt_errtbl[i].status == status) {
336*4882a593Smuzhiyun res->errno = mnt_errtbl[i].errno;
337*4882a593Smuzhiyun return 0;
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun dprintk("NFS: unrecognized MNT status code: %u\n", status);
342*4882a593Smuzhiyun res->errno = -EACCES;
343*4882a593Smuzhiyun return 0;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
decode_fhandle(struct xdr_stream * xdr,struct mountres * res)346*4882a593Smuzhiyun static int decode_fhandle(struct xdr_stream *xdr, struct mountres *res)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun struct nfs_fh *fh = res->fh;
349*4882a593Smuzhiyun __be32 *p;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun p = xdr_inline_decode(xdr, NFS2_FHSIZE);
352*4882a593Smuzhiyun if (unlikely(p == NULL))
353*4882a593Smuzhiyun return -EIO;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun fh->size = NFS2_FHSIZE;
356*4882a593Smuzhiyun memcpy(fh->data, p, NFS2_FHSIZE);
357*4882a593Smuzhiyun return 0;
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun
mnt_xdr_dec_mountres(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)360*4882a593Smuzhiyun static int mnt_xdr_dec_mountres(struct rpc_rqst *req,
361*4882a593Smuzhiyun struct xdr_stream *xdr,
362*4882a593Smuzhiyun void *data)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun struct mountres *res = data;
365*4882a593Smuzhiyun int status;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun status = decode_status(xdr, res);
368*4882a593Smuzhiyun if (unlikely(status != 0 || res->errno != 0))
369*4882a593Smuzhiyun return status;
370*4882a593Smuzhiyun return decode_fhandle(xdr, res);
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun
decode_fhs_status(struct xdr_stream * xdr,struct mountres * res)373*4882a593Smuzhiyun static int decode_fhs_status(struct xdr_stream *xdr, struct mountres *res)
374*4882a593Smuzhiyun {
375*4882a593Smuzhiyun unsigned int i;
376*4882a593Smuzhiyun u32 status;
377*4882a593Smuzhiyun __be32 *p;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
380*4882a593Smuzhiyun if (unlikely(p == NULL))
381*4882a593Smuzhiyun return -EIO;
382*4882a593Smuzhiyun status = be32_to_cpup(p);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(mnt3_errtbl); i++) {
385*4882a593Smuzhiyun if (mnt3_errtbl[i].status == status) {
386*4882a593Smuzhiyun res->errno = mnt3_errtbl[i].errno;
387*4882a593Smuzhiyun return 0;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun }
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun dprintk("NFS: unrecognized MNT3 status code: %u\n", status);
392*4882a593Smuzhiyun res->errno = -EACCES;
393*4882a593Smuzhiyun return 0;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
decode_fhandle3(struct xdr_stream * xdr,struct mountres * res)396*4882a593Smuzhiyun static int decode_fhandle3(struct xdr_stream *xdr, struct mountres *res)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun struct nfs_fh *fh = res->fh;
399*4882a593Smuzhiyun u32 size;
400*4882a593Smuzhiyun __be32 *p;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
403*4882a593Smuzhiyun if (unlikely(p == NULL))
404*4882a593Smuzhiyun return -EIO;
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun size = be32_to_cpup(p);
407*4882a593Smuzhiyun if (size > NFS3_FHSIZE || size == 0)
408*4882a593Smuzhiyun return -EIO;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun p = xdr_inline_decode(xdr, size);
411*4882a593Smuzhiyun if (unlikely(p == NULL))
412*4882a593Smuzhiyun return -EIO;
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun fh->size = size;
415*4882a593Smuzhiyun memcpy(fh->data, p, size);
416*4882a593Smuzhiyun return 0;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
decode_auth_flavors(struct xdr_stream * xdr,struct mountres * res)419*4882a593Smuzhiyun static int decode_auth_flavors(struct xdr_stream *xdr, struct mountres *res)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun rpc_authflavor_t *flavors = res->auth_flavors;
422*4882a593Smuzhiyun unsigned int *count = res->auth_count;
423*4882a593Smuzhiyun u32 entries, i;
424*4882a593Smuzhiyun __be32 *p;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun if (*count == 0)
427*4882a593Smuzhiyun return 0;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4);
430*4882a593Smuzhiyun if (unlikely(p == NULL))
431*4882a593Smuzhiyun return -EIO;
432*4882a593Smuzhiyun entries = be32_to_cpup(p);
433*4882a593Smuzhiyun dprintk("NFS: received %u auth flavors\n", entries);
434*4882a593Smuzhiyun if (entries > NFS_MAX_SECFLAVORS)
435*4882a593Smuzhiyun entries = NFS_MAX_SECFLAVORS;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun p = xdr_inline_decode(xdr, 4 * entries);
438*4882a593Smuzhiyun if (unlikely(p == NULL))
439*4882a593Smuzhiyun return -EIO;
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun if (entries > *count)
442*4882a593Smuzhiyun entries = *count;
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun for (i = 0; i < entries; i++) {
445*4882a593Smuzhiyun flavors[i] = be32_to_cpup(p++);
446*4882a593Smuzhiyun dprintk("NFS: auth flavor[%u]: %d\n", i, flavors[i]);
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun *count = i;
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun return 0;
451*4882a593Smuzhiyun }
452*4882a593Smuzhiyun
mnt_xdr_dec_mountres3(struct rpc_rqst * req,struct xdr_stream * xdr,void * data)453*4882a593Smuzhiyun static int mnt_xdr_dec_mountres3(struct rpc_rqst *req,
454*4882a593Smuzhiyun struct xdr_stream *xdr,
455*4882a593Smuzhiyun void *data)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun struct mountres *res = data;
458*4882a593Smuzhiyun int status;
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun status = decode_fhs_status(xdr, res);
461*4882a593Smuzhiyun if (unlikely(status != 0 || res->errno != 0))
462*4882a593Smuzhiyun return status;
463*4882a593Smuzhiyun status = decode_fhandle3(xdr, res);
464*4882a593Smuzhiyun if (unlikely(status != 0)) {
465*4882a593Smuzhiyun res->errno = -EBADHANDLE;
466*4882a593Smuzhiyun return 0;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun return decode_auth_flavors(xdr, res);
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun static const struct rpc_procinfo mnt_procedures[] = {
472*4882a593Smuzhiyun [MOUNTPROC_MNT] = {
473*4882a593Smuzhiyun .p_proc = MOUNTPROC_MNT,
474*4882a593Smuzhiyun .p_encode = mnt_xdr_enc_dirpath,
475*4882a593Smuzhiyun .p_decode = mnt_xdr_dec_mountres,
476*4882a593Smuzhiyun .p_arglen = MNT_enc_dirpath_sz,
477*4882a593Smuzhiyun .p_replen = MNT_dec_mountres_sz,
478*4882a593Smuzhiyun .p_statidx = MOUNTPROC_MNT,
479*4882a593Smuzhiyun .p_name = "MOUNT",
480*4882a593Smuzhiyun },
481*4882a593Smuzhiyun [MOUNTPROC_UMNT] = {
482*4882a593Smuzhiyun .p_proc = MOUNTPROC_UMNT,
483*4882a593Smuzhiyun .p_encode = mnt_xdr_enc_dirpath,
484*4882a593Smuzhiyun .p_arglen = MNT_enc_dirpath_sz,
485*4882a593Smuzhiyun .p_statidx = MOUNTPROC_UMNT,
486*4882a593Smuzhiyun .p_name = "UMOUNT",
487*4882a593Smuzhiyun },
488*4882a593Smuzhiyun };
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun static const struct rpc_procinfo mnt3_procedures[] = {
491*4882a593Smuzhiyun [MOUNTPROC3_MNT] = {
492*4882a593Smuzhiyun .p_proc = MOUNTPROC3_MNT,
493*4882a593Smuzhiyun .p_encode = mnt_xdr_enc_dirpath,
494*4882a593Smuzhiyun .p_decode = mnt_xdr_dec_mountres3,
495*4882a593Smuzhiyun .p_arglen = MNT_enc_dirpath_sz,
496*4882a593Smuzhiyun .p_replen = MNT_dec_mountres3_sz,
497*4882a593Smuzhiyun .p_statidx = MOUNTPROC3_MNT,
498*4882a593Smuzhiyun .p_name = "MOUNT",
499*4882a593Smuzhiyun },
500*4882a593Smuzhiyun [MOUNTPROC3_UMNT] = {
501*4882a593Smuzhiyun .p_proc = MOUNTPROC3_UMNT,
502*4882a593Smuzhiyun .p_encode = mnt_xdr_enc_dirpath,
503*4882a593Smuzhiyun .p_arglen = MNT_enc_dirpath_sz,
504*4882a593Smuzhiyun .p_statidx = MOUNTPROC3_UMNT,
505*4882a593Smuzhiyun .p_name = "UMOUNT",
506*4882a593Smuzhiyun },
507*4882a593Smuzhiyun };
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun static unsigned int mnt_counts[ARRAY_SIZE(mnt_procedures)];
510*4882a593Smuzhiyun static const struct rpc_version mnt_version1 = {
511*4882a593Smuzhiyun .number = 1,
512*4882a593Smuzhiyun .nrprocs = ARRAY_SIZE(mnt_procedures),
513*4882a593Smuzhiyun .procs = mnt_procedures,
514*4882a593Smuzhiyun .counts = mnt_counts,
515*4882a593Smuzhiyun };
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun static unsigned int mnt3_counts[ARRAY_SIZE(mnt3_procedures)];
518*4882a593Smuzhiyun static const struct rpc_version mnt_version3 = {
519*4882a593Smuzhiyun .number = 3,
520*4882a593Smuzhiyun .nrprocs = ARRAY_SIZE(mnt3_procedures),
521*4882a593Smuzhiyun .procs = mnt3_procedures,
522*4882a593Smuzhiyun .counts = mnt3_counts,
523*4882a593Smuzhiyun };
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun static const struct rpc_version *mnt_version[] = {
526*4882a593Smuzhiyun NULL,
527*4882a593Smuzhiyun &mnt_version1,
528*4882a593Smuzhiyun NULL,
529*4882a593Smuzhiyun &mnt_version3,
530*4882a593Smuzhiyun };
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun static struct rpc_stat mnt_stats;
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun static const struct rpc_program mnt_program = {
535*4882a593Smuzhiyun .name = "mount",
536*4882a593Smuzhiyun .number = NFS_MNT_PROGRAM,
537*4882a593Smuzhiyun .nrvers = ARRAY_SIZE(mnt_version),
538*4882a593Smuzhiyun .version = mnt_version,
539*4882a593Smuzhiyun .stats = &mnt_stats,
540*4882a593Smuzhiyun };
541