Newer
Older
}
static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
uint32_t bmlen;
int status;
status = decode_op_hdr(xdr, OP_CREATE);
if (status)
return status;
if ((status = decode_change_info(xdr, cinfo)))
return status;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
p = xdr_inline_decode(xdr, bmlen << 2);
if (likely(p))
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
{
uint32_t attrlen, bitmap[2] = {0};
int status;
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto xdr_error;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto xdr_error;
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
goto xdr_error;
if ((status = decode_attr_supported(xdr, bitmap, res->attr_bitmask)) != 0)
goto xdr_error;
if ((status = decode_attr_link_support(xdr, bitmap, &res->has_links)) != 0)
goto xdr_error;
if ((status = decode_attr_symlink_support(xdr, bitmap, &res->has_symlinks)) != 0)
goto xdr_error;
if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0)
goto xdr_error;
status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
dprintk("%s: xdr returned %d!\n", __func__, -status);
static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
{
uint32_t attrlen, bitmap[2] = {0};
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto xdr_error;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto xdr_error;
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
goto xdr_error;
if ((status = decode_attr_files_avail(xdr, bitmap, &fsstat->afiles)) != 0)
goto xdr_error;
if ((status = decode_attr_files_free(xdr, bitmap, &fsstat->ffiles)) != 0)
goto xdr_error;
if ((status = decode_attr_files_total(xdr, bitmap, &fsstat->tfiles)) != 0)
goto xdr_error;
if ((status = decode_attr_space_avail(xdr, bitmap, &fsstat->abytes)) != 0)
goto xdr_error;
if ((status = decode_attr_space_free(xdr, bitmap, &fsstat->fbytes)) != 0)
goto xdr_error;
if ((status = decode_attr_space_total(xdr, bitmap, &fsstat->tbytes)) != 0)
goto xdr_error;
status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
dprintk("%s: xdr returned %d!\n", __func__, -status);
return status;
}
static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
{
uint32_t attrlen, bitmap[2] = {0};
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto xdr_error;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto xdr_error;
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
goto xdr_error;
if ((status = decode_attr_maxlink(xdr, bitmap, &pathconf->max_link)) != 0)
goto xdr_error;
if ((status = decode_attr_maxname(xdr, bitmap, &pathconf->max_namelen)) != 0)
goto xdr_error;
status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
dprintk("%s: xdr returned %d!\n", __func__, -status);
static int decode_getfattr_attrs(struct xdr_stream *xdr, uint32_t *bitmap,
struct nfs_fattr *fattr, struct nfs_fh *fh,
const struct nfs_server *server, int may_sleep)
int status;
umode_t fmode = 0;
status = decode_attr_type(xdr, bitmap, &type);
if (status < 0)

Trond Myklebust
committed
fattr->mode = 0;
if (status != 0) {
fattr->mode |= nfs_type2fmt[type];
fattr->valid |= status;
}
status = decode_attr_change(xdr, bitmap, &fattr->change_attr);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_size(xdr, bitmap, &fattr->size);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_fsid(xdr, bitmap, &fattr->fsid);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
err = 0;
status = decode_attr_error(xdr, bitmap, &err);
if (status < 0)
goto xdr_error;
if (err == -NFS4ERR_WRONGSEC)
nfs_fixup_secinfo_attributes(fattr, fh);
status = decode_attr_filehandle(xdr, bitmap, fh);
if (status < 0)
goto xdr_error;
status = decode_attr_fileid(xdr, bitmap, &fattr->fileid);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_fs_locations(xdr, bitmap, container_of(fattr,
struct nfs4_fs_locations,

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_mode(xdr, bitmap, &fmode);
if (status < 0)

Trond Myklebust
committed
if (status != 0) {
fattr->mode |= fmode;
fattr->valid |= status;
}
status = decode_attr_nlink(xdr, bitmap, &fattr->nlink);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_owner(xdr, bitmap, server, &fattr->uid, may_sleep);

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_group(xdr, bitmap, server, &fattr->gid, may_sleep);

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_rdev(xdr, bitmap, &fattr->rdev);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_space_used(xdr, bitmap, &fattr->du.nfs3.used);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_time_access(xdr, bitmap, &fattr->atime);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_time_metadata(xdr, bitmap, &fattr->ctime);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_time_modify(xdr, bitmap, &fattr->mtime);
if (status < 0)

Trond Myklebust
committed
fattr->valid |= status;
status = decode_attr_mounted_on_fileid(xdr, bitmap, &fattr->mounted_on_fileid);
fattr->valid |= status;
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
xdr_error:
dprintk("%s: xdr returned %d\n", __func__, -status);
return status;
}
static int decode_getfattr_generic(struct xdr_stream *xdr, struct nfs_fattr *fattr,
struct nfs_fh *fh, const struct nfs_server *server, int may_sleep)
{
__be32 *savep;
uint32_t attrlen,
bitmap[2] = {0};
int status;
status = decode_op_hdr(xdr, OP_GETATTR);
if (status < 0)
goto xdr_error;
status = decode_attr_bitmap(xdr, bitmap);
if (status < 0)
goto xdr_error;
status = decode_attr_length(xdr, &attrlen, &savep);
if (status < 0)
goto xdr_error;
status = decode_getfattr_attrs(xdr, bitmap, fattr, fh, server, may_sleep);
if (status < 0)
goto xdr_error;
status = verify_attr_len(xdr, savep, attrlen);
dprintk("%s: xdr returned %d\n", __func__, -status);
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr,
const struct nfs_server *server, int may_sleep)
{
return decode_getfattr_generic(xdr, fattr, NULL, server, may_sleep);
}
4259
4260
4261
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276
4277
4278
4279
4280
4281
4282
4283
4284
4285
4286
4287
4288
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
4309
4310
4311
4312
4313
/*
* Decode potentially multiple layout types. Currently we only support
* one layout driver per file system.
*/
static int decode_first_pnfs_layout_type(struct xdr_stream *xdr,
uint32_t *layouttype)
{
uint32_t *p;
int num;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
num = be32_to_cpup(p);
/* pNFS is not supported by the underlying file system */
if (num == 0) {
*layouttype = 0;
return 0;
}
if (num > 1)
printk(KERN_INFO "%s: Warning: Multiple pNFS layout drivers "
"per filesystem not supported\n", __func__);
/* Decode and set first layout type, move xdr->p past unused types */
p = xdr_inline_decode(xdr, num * 4);
if (unlikely(!p))
goto out_overflow;
*layouttype = be32_to_cpup(p);
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
/*
* The type of file system exported.
* Note we must ensure that layouttype is set in any non-error case.
*/
static int decode_attr_pnfstype(struct xdr_stream *xdr, uint32_t *bitmap,
uint32_t *layouttype)
{
int status = 0;
dprintk("%s: bitmap is %x\n", __func__, bitmap[1]);
if (unlikely(bitmap[1] & (FATTR4_WORD1_FS_LAYOUT_TYPES - 1U)))
return -EIO;
if (bitmap[1] & FATTR4_WORD1_FS_LAYOUT_TYPES) {
status = decode_first_pnfs_layout_type(xdr, layouttype);
bitmap[1] &= ~FATTR4_WORD1_FS_LAYOUT_TYPES;
} else
*layouttype = 0;
return status;
}
static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
4317
4318
4319
4320
4321
4322
4323
4324
4325
4326
4327
4328
4329
4330
4331
4332
4333
4334
4335
4336
4337
4338
uint32_t attrlen, bitmap[2];
int status;
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto xdr_error;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto xdr_error;
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
goto xdr_error;
fsinfo->rtmult = fsinfo->wtmult = 512; /* ??? */
if ((status = decode_attr_lease_time(xdr, bitmap, &fsinfo->lease_time)) != 0)
goto xdr_error;
if ((status = decode_attr_maxfilesize(xdr, bitmap, &fsinfo->maxfilesize)) != 0)
goto xdr_error;
if ((status = decode_attr_maxread(xdr, bitmap, &fsinfo->rtmax)) != 0)
goto xdr_error;
fsinfo->rtpref = fsinfo->dtpref = fsinfo->rtmax;
if ((status = decode_attr_maxwrite(xdr, bitmap, &fsinfo->wtmax)) != 0)
goto xdr_error;
fsinfo->wtpref = fsinfo->wtmax;
status = decode_attr_time_delta(xdr, bitmap, &fsinfo->time_delta);
if (status != 0)
goto xdr_error;
status = decode_attr_pnfstype(xdr, bitmap, &fsinfo->layouttype);
if (status != 0)
goto xdr_error;
status = verify_attr_len(xdr, savep, attrlen);
xdr_error:
dprintk("%s: xdr returned %d!\n", __func__, -status);
return status;
}
static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
/* Zero handle first to allow comparisons */
memset(fh, 0, sizeof(*fh));
status = decode_op_hdr(xdr, OP_GETFH);
if (status)
return status;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
if (len > NFS4_FHSIZE)
return -EIO;
fh->size = len;
p = xdr_inline_decode(xdr, len);
if (unlikely(!p))
goto out_overflow;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
int status;
status = decode_op_hdr(xdr, OP_LINK);
if (status)
return status;
return decode_change_info(xdr, cinfo);
}
/*
* We create the owner, so we know a proper owner.id length is 4.
*/
static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
p = xdr_inline_decode(xdr, 32); /* read 32 bytes */
if (unlikely(!p))
goto out_overflow;
p = xdr_decode_hyper(p, &offset); /* read 2 8-byte long words */
type = be32_to_cpup(p++); /* 4 byte read */
if (fl != NULL) { /* manipulate file lock */
fl->fl_start = (loff_t)offset;
fl->fl_end = fl->fl_start + (loff_t)length - 1;
if (length == ~(uint64_t)0)
fl->fl_end = OFFSET_MAX;
fl->fl_type = F_WRLCK;
if (type & 1)
fl->fl_type = F_RDLCK;
fl->fl_pid = 0;
}
p = xdr_decode_hyper(p, &clientid); /* read 8 bytes */
namelen = be32_to_cpup(p); /* read 4 bytes */ /* have read all 32 bytes now */
p = xdr_inline_decode(xdr, namelen); /* variable size field */
if (likely(p))
return -NFS4ERR_DENIED;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
{
int status;
status = decode_op_hdr(xdr, OP_LOCK);
if (status == -EIO)
goto out;
status = decode_stateid(xdr, &res->stateid);
if (unlikely(status))
goto out;
status = decode_lock_denied(xdr, NULL);
if (res->open_seqid != NULL)
nfs_increment_open_seqid(status, res->open_seqid);
nfs_increment_lock_seqid(status, res->lock_seqid);
out:
static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
{
int status;
status = decode_op_hdr(xdr, OP_LOCKT);
if (status == -NFS4ERR_DENIED)
return decode_lock_denied(xdr, res->denied);
static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
{
int status;
status = decode_op_hdr(xdr, OP_LOCKU);
if (status != -EIO)
nfs_increment_lock_seqid(status, res->seqid);
if (status == 0)
status = decode_stateid(xdr, &res->stateid);
static int decode_release_lockowner(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_RELEASE_LOCKOWNER);
}
static int decode_lookup(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_LOOKUP);
}
/* This is too sick! */
static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
{
p = xdr_inline_decode(xdr, 12);
if (unlikely(!p))
goto out_overflow;
*maxsize = (uint64_t)nblocks * (uint64_t)blocksize;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
int status;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
delegation_type = be32_to_cpup(p);
if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
res->delegation_type = 0;
return 0;
}
status = decode_stateid(xdr, &res->delegation);
if (unlikely(status))
return status;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
res->do_recall = be32_to_cpup(p);
case NFS4_OPEN_DELEGATE_READ:
res->delegation_type = FMODE_READ;
break;
case NFS4_OPEN_DELEGATE_WRITE:
res->delegation_type = FMODE_WRITE|FMODE_READ;
if (decode_space_limit(xdr, &res->maxsize) < 0)
return decode_ace(xdr, NULL, res->server->nfs_client);
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
uint32_t savewords, bmlen, i;
if (status != -EIO)
nfs_increment_open_seqid(status, res->seqid);
if (!status)
status = decode_stateid(xdr, &res->stateid);
if (unlikely(status))
p = xdr_inline_decode(xdr, 8);
if (unlikely(!p))
goto out_overflow;
p = xdr_inline_decode(xdr, bmlen << 2);
if (unlikely(!p))
goto out_overflow;
savewords = min_t(uint32_t, bmlen, NFS4_BITMAP_SIZE);
for (i = 0; i < savewords; ++i)
for (; i < NFS4_BITMAP_SIZE; i++)
res->attrset[i] = 0;
dprintk("%s: Bitmap too large! Length = %u\n", __func__, bmlen);
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
{
int status;
status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
if (status != -EIO)
nfs_increment_open_seqid(status, res->seqid);
if (!status)
status = decode_stateid(xdr, &res->stateid);
return status;
}
static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
{
int status;
status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
if (status != -EIO)
nfs_increment_open_seqid(status, res->seqid);
if (!status)
status = decode_stateid(xdr, &res->stateid);
return status;
}
static int decode_putfh(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_PUTFH);
}
static int decode_putrootfh(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_PUTROOTFH);
}
static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
{
struct kvec *iov = req->rq_rcv_buf.head;
uint32_t count, eof, recvd, hdrlen;
int status;
status = decode_op_hdr(xdr, OP_READ);
if (status)
return status;
p = xdr_inline_decode(xdr, 8);
if (unlikely(!p))
goto out_overflow;
hdrlen = (u8 *) xdr->p - (u8 *) iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen;
if (count > recvd) {
dprintk("NFS: server cheating in read reply: "
"count %u > recvd %u\n", count, recvd);
count = recvd;
eof = 0;
}
xdr_read_pages(xdr, count);
res->eof = eof;
res->count = count;
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs4_readdir_res *readdir)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct kvec *iov = rcvbuf->head;
size_t hdrlen;
u32 recvd, pglen = rcvbuf->page_len;
int status;
if (!status)
status = decode_verifier(xdr, readdir->verifier.data);
if (unlikely(status))
dprintk("%s: verifier = %08x:%08x\n",
__func__,
((u32 *)readdir->verifier.data)[0],
((u32 *)readdir->verifier.data)[1]);
hdrlen = (char *) xdr->p - (char *) iov->iov_base;
recvd = rcvbuf->len - hdrlen;
if (pglen > recvd)
pglen = recvd;
xdr_read_pages(xdr, pglen);
return pglen;
}
static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct kvec *iov = rcvbuf->head;
size_t hdrlen;
u32 len, recvd;
int status;
status = decode_op_hdr(xdr, OP_READLINK);
if (status)
return status;
/* Convert length of symlink */
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
dprintk("nfs: server returned giant symlink!\n");
return -ENAMETOOLONG;
}
hdrlen = (char *) xdr->p - (char *) iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen;
if (recvd < len) {
dprintk("NFS: server cheating in readlink reply: "
"count %u > recvd %u\n", len, recvd);
return -EIO;
}
xdr_read_pages(xdr, len);
/*
* The XDR encode routine has set things up so that
* the link text will be copied directly into the
* buffer. We just have to do overflow-checking,
* and and null-terminate the text (the VFS expects
* null-termination).
*/
xdr_terminate_string(rcvbuf, len);
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
}
static int decode_remove(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
int status;
status = decode_op_hdr(xdr, OP_REMOVE);
if (status)
goto out;
status = decode_change_info(xdr, cinfo);
out:
return status;
}
static int decode_rename(struct xdr_stream *xdr, struct nfs4_change_info *old_cinfo,
struct nfs4_change_info *new_cinfo)
{
int status;
status = decode_op_hdr(xdr, OP_RENAME);
if (status)
goto out;
if ((status = decode_change_info(xdr, old_cinfo)))
goto out;
status = decode_change_info(xdr, new_cinfo);
out:
return status;
}
static int decode_renew(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_RENEW);
}
static int
decode_restorefh(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_RESTOREFH);
}
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
size_t *acl_len)
{
uint32_t attrlen,
bitmap[2] = {0};
struct kvec *iov = req->rq_rcv_buf.head;
int status;
*acl_len = 0;
if ((status = decode_op_hdr(xdr, OP_GETATTR)) != 0)
goto out;
if ((status = decode_attr_bitmap(xdr, bitmap)) != 0)
goto out;
if ((status = decode_attr_length(xdr, &attrlen, &savep)) != 0)
goto out;
if (unlikely(bitmap[0] & (FATTR4_WORD0_ACL - 1U)))
return -EIO;
if (likely(bitmap[0] & FATTR4_WORD0_ACL)) {
size_t hdrlen;
u32 recvd;
/* We ignore &savep and don't do consistency checks on
* the attr length. Let userspace figure it out.... */
hdrlen = (u8 *)xdr->p - (u8 *)iov->iov_base;
recvd = req->rq_rcv_buf.len - hdrlen;
if (attrlen > recvd) {
dprintk("NFS: server cheating in getattr"
" acl reply: attrlen %u > recvd %u\n",
attrlen, recvd);
return -EINVAL;
}
xdr_read_pages(xdr, attrlen);
*acl_len = attrlen;
out:
return status;
}
static int
decode_savefh(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_SAVEFH);
}
static int decode_setattr(struct xdr_stream *xdr)
uint32_t bmlen;
int status;
status = decode_op_hdr(xdr, OP_SETATTR);
if (status)
return status;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
p = xdr_inline_decode(xdr, bmlen << 2);
if (likely(p))
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
static int decode_setclientid(struct xdr_stream *xdr, struct nfs4_setclientid_res *res)
p = xdr_inline_decode(xdr, 8);
if (unlikely(!p))
goto out_overflow;
dprintk("nfs: decode_setclientid: Server returned operation"
p = xdr_inline_decode(xdr, 8 + NFS4_VERIFIER_SIZE);
if (unlikely(!p))
goto out_overflow;
p = xdr_decode_hyper(p, &res->clientid);
memcpy(res->confirm.data, p, NFS4_VERIFIER_SIZE);
} else if (nfserr == NFSERR_CLID_INUSE) {
uint32_t len;
/* skip netid string */
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
p = xdr_inline_decode(xdr, len);
if (unlikely(!p))
goto out_overflow;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
p = xdr_inline_decode(xdr, len);
if (unlikely(!p))
goto out_overflow;
return nfs4_stat_to_errno(nfserr);
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_setclientid_confirm(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_SETCLIENTID_CONFIRM);
}
static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
{
int status;
status = decode_op_hdr(xdr, OP_WRITE);
if (status)
return status;
p = xdr_inline_decode(xdr, 16);
if (unlikely(!p))
goto out_overflow;
res->count = be32_to_cpup(p++);
res->verf->committed = be32_to_cpup(p++);
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
static int decode_delegreturn(struct xdr_stream *xdr)
{
return decode_op_hdr(xdr, OP_DELEGRETURN);
}
4911
4912
4913
4914
4915
4916
4917
4918
4919
4920
4921
4922
4923
4924
4925
4926
4927
4928
4929
4930
4931
4932
4933
4934
4935
4936
4937
4938
4939
4940
4941
4942
4943
4944
4945
4946
static int decode_secinfo_gss(struct xdr_stream *xdr, struct nfs4_secinfo_flavor *flavor)
{
__be32 *p;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
flavor->gss.sec_oid4.len = be32_to_cpup(p);
if (flavor->gss.sec_oid4.len > GSS_OID_MAX_LEN)
goto out_err;
p = xdr_inline_decode(xdr, flavor->gss.sec_oid4.len);
if (unlikely(!p))
goto out_overflow;
memcpy(flavor->gss.sec_oid4.data, p, flavor->gss.sec_oid4.len);
p = xdr_inline_decode(xdr, 8);
if (unlikely(!p))
goto out_overflow;
flavor->gss.qop4 = be32_to_cpup(p++);
flavor->gss.service = be32_to_cpup(p);
return 0;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
out_err:
return -EINVAL;
}
static int decode_secinfo(struct xdr_stream *xdr, struct nfs4_secinfo_res *res)
{
struct nfs4_secinfo_flavor *sec_flavor;
int status;
__be32 *p;
int i, num_flavors;
status = decode_op_hdr(xdr, OP_SECINFO);
if (status)
goto out;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
res->flavors->num_flavors = 0;
num_flavors = be32_to_cpup(p);
for (i = 0; i < num_flavors; i++) {
if ((char *)&sec_flavor[1] - (char *)res->flavors > PAGE_SIZE)
break;
p = xdr_inline_decode(xdr, 4);
if (unlikely(!p))
goto out_overflow;
sec_flavor->flavor = be32_to_cpup(p);
if (sec_flavor->flavor == RPC_AUTH_GSS) {
status = decode_secinfo_gss(xdr, sec_flavor);
if (status)
goto out;
res->flavors->num_flavors++;
out:
return status;
out_overflow:
print_overflow_msg(__func__, xdr);
return -EIO;
}
#if defined(CONFIG_NFS_V4_1)
static int decode_exchange_id(struct xdr_stream *xdr,
struct nfs41_exchange_id_res *res)
{
__be32 *p;
uint32_t dummy;
char *dummy_str;
int status;
struct nfs_client *clp = res->client;
status = decode_op_hdr(xdr, OP_EXCHANGE_ID);
if (status)
return status;
p = xdr_inline_decode(xdr, 8);
if (unlikely(!p))
goto out_overflow;