static int decode_filename_inline(struct xdr_stream *xdr, const char **name, u32 *length) { __be32 *p; u32 count; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; count = be32_to_cpup(p); if (count > NFS3_MAXNAMLEN) goto out_nametoolong; p = xdr_inline_decode(xdr, count); if (unlikely(p == NULL)) goto out_overflow; *name = (const char *)p; *length = count; return 0; out_nametoolong: dprintk("NFS: returned filename too long: %u\n", count); return -ENAMETOOLONG; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_fattr3(struct xdr_stream *xdr, struct nfs_fattr *fattr) { umode_t fmode; __be32 *p; p = xdr_inline_decode(xdr, NFS3_fattr_sz << 2); if (unlikely(p == NULL)) goto out_overflow; p = xdr_decode_ftype3(p, &fmode); fattr->mode = (be32_to_cpup(p++) & ~S_IFMT) | fmode; fattr->nlink = be32_to_cpup(p++); fattr->uid = be32_to_cpup(p++); fattr->gid = be32_to_cpup(p++); p = xdr_decode_size3(p, &fattr->size); p = xdr_decode_size3(p, &fattr->du.nfs3.used); p = xdr_decode_specdata3(p, &fattr->rdev); p = xdr_decode_hyper(p, &fattr->fsid.major); fattr->fsid.minor = 0; p = xdr_decode_fileid3(p, &fattr->fileid); p = xdr_decode_nfstime3(p, &fattr->atime); p = xdr_decode_nfstime3(p, &fattr->mtime); xdr_decode_nfstime3(p, &fattr->ctime); fattr->valid |= NFS_ATTR_FATTR_V3; return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_nfspath3(struct xdr_stream *xdr) { u32 recvd, count; size_t hdrlen; __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; count = be32_to_cpup(p); if (unlikely(count >= xdr->buf->page_len || count > NFS3_MAXPATHLEN)) goto out_nametoolong; hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base; recvd = xdr->buf->len - hdrlen; if (unlikely(count > recvd)) goto out_cheating; xdr_read_pages(xdr, count); xdr_terminate_string(xdr->buf, count); return 0; out_nametoolong: dprintk("NFS: returned pathname too long: %u\n", count); return -ENAMETOOLONG; out_cheating: dprintk("NFS: server cheating in pathname result: " "count %u > recvd %u\n", count, recvd); return -EIO; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_path(struct xdr_stream *xdr) { u32 length, recvd; __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; length = be32_to_cpup(p); if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN)) goto out_size; recvd = xdr_read_pages(xdr, length); if (unlikely(length > recvd)) goto out_cheating; xdr_terminate_string(xdr->buf, length); return 0; out_size: dprintk("NFS: returned pathname too long: %u\n", length); return -ENAMETOOLONG; out_cheating: dprintk("NFS: server cheating in pathname result: " "length %u > received %u\n", length, recvd); return -EIO; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_fsinfo3resok(struct xdr_stream *xdr, struct nfs_fsinfo *result) { __be32 *p; p = xdr_inline_decode(xdr, 4 * 7 + 8 + 8 + 4); if (unlikely(p == NULL)) goto out_overflow; result->rtmax = be32_to_cpup(p++); result->rtpref = be32_to_cpup(p++); result->rtmult = be32_to_cpup(p++); result->wtmax = be32_to_cpup(p++); result->wtpref = be32_to_cpup(p++); result->wtmult = be32_to_cpup(p++); result->dtpref = be32_to_cpup(p++); p = xdr_decode_size3(p, &result->maxfilesize); xdr_decode_nfstime3(p, &result->time_delta); result->lease_time = 0; return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_cookie(struct xdr_stream *xdr, struct nlm_cookie *cookie) { u32 length; __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; length = be32_to_cpup(p++); /* apparently HPUX can return empty cookies */ if (length == 0) goto out_hpux; if (length > NLM_MAXCOOKIELEN) goto out_size; p = xdr_inline_decode(xdr, length); if (unlikely(p == NULL)) goto out_overflow; cookie->len = length; memcpy(cookie->data, p, length); return 0; out_hpux: cookie->len = 4; memset(cookie->data, 0, 4); return 0; out_size: dprintk("NFS: returned cookie was too long: %u\n", length); return -EIO; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/* * typedef opaque nfsdata<>; */ static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result) { u32 recvd, count; __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; count = be32_to_cpup(p); recvd = xdr_read_pages(xdr, count); if (unlikely(count > recvd)) goto out_cheating; out: result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */ result->count = count; return count; out_cheating: dprintk("NFS: server cheating in read result: " "count %u > recvd %u\n", count, recvd); count = recvd; goto out; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/* * enum stat { * NFS_OK = 0, * NFSERR_PERM = 1, * NFSERR_NOENT = 2, * NFSERR_IO = 5, * NFSERR_NXIO = 6, * NFSERR_ACCES = 13, * NFSERR_EXIST = 17, * NFSERR_NODEV = 19, * NFSERR_NOTDIR = 20, * NFSERR_ISDIR = 21, * NFSERR_FBIG = 27, * NFSERR_NOSPC = 28, * NFSERR_ROFS = 30, * NFSERR_NAMETOOLONG = 63, * NFSERR_NOTEMPTY = 66, * NFSERR_DQUOT = 69, * NFSERR_STALE = 70, * NFSERR_WFLUSH = 99 * }; */ static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; *status = be32_to_cpup(p); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_writeverf3(struct xdr_stream *xdr, __be32 *verifier) { __be32 *p; p = xdr_inline_decode(xdr, NFS3_WRITEVERFSIZE); if (unlikely(p == NULL)) goto out_overflow; memcpy(verifier, p, NFS3_WRITEVERFSIZE); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_uint64(struct xdr_stream *xdr, u64 *value) { __be32 *p; p = xdr_inline_decode(xdr, 8); if (unlikely(p == NULL)) goto out_overflow; xdr_decode_hyper(p, value); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_uint32(struct xdr_stream *xdr, u32 *value) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; *value = be32_to_cpup(p); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_post_op_fh3(struct xdr_stream *xdr, struct nfs_fh *fh) { __be32 *p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; if (*p != xdr_zero) return decode_nfs_fh3(xdr, fh); zero_nfs_fh3(fh); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_pre_op_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; if (*p != xdr_zero) return decode_wcc_attr(xdr, fattr); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/* * CB_SEQUENCE4resok * * struct CB_SEQUENCE4resok { * sessionid4 csr_sessionid; * sequenceid4 csr_sequenceid; * slotid4 csr_slotid; * slotid4 csr_highest_slotid; * slotid4 csr_target_highest_slotid; * }; * * union CB_SEQUENCE4res switch (nfsstat4 csr_status) { * case NFS4_OK: * CB_SEQUENCE4resok csr_resok4; * default: * void; * }; * * Our current back channel implmentation supports a single backchannel * with a single slot. */ static int decode_cb_sequence4resok(struct xdr_stream *xdr, struct nfsd4_callback *cb) { struct nfsd4_session *session = cb->cb_clp->cl_cb_session; struct nfs4_sessionid id; int status; __be32 *p; u32 dummy; status = -ESERVERFAULT; /* * If the server returns different values for sessionID, slotID or * sequence number, the server is looney tunes. */ p = xdr_inline_decode(xdr, NFS4_MAX_SESSIONID_LEN + 4 + 4 + 4 + 4); if (unlikely(p == NULL)) goto out_overflow; memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN); if (memcmp(id.data, session->se_sessionid.data, NFS4_MAX_SESSIONID_LEN) != 0) { dprintk("NFS: %s Invalid session id\n", __func__); goto out; } p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN); dummy = be32_to_cpup(p++); if (dummy != session->se_cb_seq_nr) { dprintk("NFS: %s Invalid sequence number\n", __func__); goto out; } dummy = be32_to_cpup(p++); if (dummy != 0) { dprintk("NFS: %s Invalid slotid\n", __func__); goto out; } /* * FIXME: process highest slotid and target highest slotid */ status = 0; out: if (status) nfsd4_mark_cb_fault(cb->cb_clp, status); return status; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh) { __be32 *p; p = xdr_inline_decode(xdr, NFS2_FHSIZE); if (unlikely(p == NULL)) goto out_overflow; fh->size = NFS2_FHSIZE; memcpy(fh->data, p, NFS2_FHSIZE); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_pathconf3resok(struct xdr_stream *xdr, struct nfs_pathconf *result) { __be32 *p; p = xdr_inline_decode(xdr, 4 * 6); if (unlikely(p == NULL)) goto out_overflow; result->max_link = be32_to_cpup(p++); result->max_namelen = be32_to_cpup(p); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_nlm4_holder(struct xdr_stream *xdr, struct nlm_res *result) { struct nlm_lock *lock = &result->lock; struct file_lock *fl = &lock->fl; u64 l_offset, l_len; u32 exclusive; int error; __be32 *p; s32 end; memset(lock, 0, sizeof(*lock)); locks_init_lock(fl); p = xdr_inline_decode(xdr, 4 + 4); if (unlikely(p == NULL)) goto out_overflow; exclusive = be32_to_cpup(p++); lock->svid = be32_to_cpup(p); fl->fl_pid = (pid_t)lock->svid; error = decode_netobj(xdr, &lock->oh); if (unlikely(error)) goto out; p = xdr_inline_decode(xdr, 8 + 8); if (unlikely(p == NULL)) goto out_overflow; fl->fl_flags = FL_POSIX; fl->fl_type = exclusive != 0 ? F_WRLCK : F_RDLCK; p = xdr_decode_hyper(p, &l_offset); xdr_decode_hyper(p, &l_len); end = l_offset + l_len - 1; fl->fl_start = (loff_t)l_offset; if (l_len == 0 || end < 0) fl->fl_end = OFFSET_MAX; else fl->fl_end = (loff_t)end; error = 0; out: return error; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/** * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in * the local page cache. * @xdr: XDR stream where entry resides * @entry: buffer to fill in with entry data * @plus: boolean indicating whether this should be a readdirplus entry * * Returns zero if successful, otherwise a negative errno value is * returned. * * This function is not invoked during READDIR reply decoding, but * rather whenever an application invokes the getdents(2) system call * on a directory already in our cache. * * 2.2.17. entry * * struct entry { * unsigned fileid; * filename name; * nfscookie cookie; * entry *nextentry; * }; */ int nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, int plus) { __be32 *p; int error; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; if (*p++ == xdr_zero) { p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; if (*p++ == xdr_zero) return -EAGAIN; entry->eof = 1; return -EBADCOOKIE; } p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; entry->ino = be32_to_cpup(p); error = decode_filename_inline(xdr, &entry->name, &entry->len); if (unlikely(error)) return error; /* * The type (size and byte order) of nfscookie isn't defined in * RFC 1094. This implementation assumes that it's an XDR uint32. */ entry->prev_cookie = entry->cookie; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; entry->cookie = be32_to_cpup(p); entry->d_type = DT_UNKNOWN; return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EAGAIN; }
/* * 2.2.18. statfsres * * union statfsres (stat status) { * case NFS_OK: * struct { * unsigned tsize; * unsigned bsize; * unsigned blocks; * unsigned bfree; * unsigned bavail; * } info; * default: * void; * }; */ static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result) { __be32 *p; p = xdr_inline_decode(xdr, NFS_info_sz << 2); if (unlikely(p == NULL)) goto out_overflow; result->tsize = be32_to_cpup(p++); result->bsize = be32_to_cpup(p++); result->blocks = be32_to_cpup(p++); result->bfree = be32_to_cpup(p++); result->bavail = be32_to_cpup(p); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
__be32 * nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; if (!ntohl(*p++)) { p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; if (!ntohl(*p++)) return ERR_PTR(-EAGAIN); entry->eof = 1; return ERR_PTR(-EBADCOOKIE); } p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; entry->ino = ntohl(*p++); entry->len = ntohl(*p++); p = xdr_inline_decode(xdr, entry->len + 4); if (unlikely(!p)) goto out_overflow; entry->name = (const char *) p; p += XDR_QUADLEN(entry->len); entry->prev_cookie = entry->cookie; entry->cookie = ntohl(*p++); p = xdr_inline_peek(xdr, 8); if (p != NULL) entry->eof = !p[0] && p[1]; else entry->eof = 0; return p; out_overflow: print_overflow_msg(__func__, xdr); return ERR_PTR(-EIO); }
static int decode_nlm4_stat(struct xdr_stream *xdr, __be32 *stat) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; if (unlikely(ntohl(*p) > ntohl(nlm4_failed))) goto out_bad_xdr; *stat = *p; return 0; out_bad_xdr: dprintk("%s: server returned invalid nlm4_stats value: %u\n", __func__, be32_to_cpup(p)); return -EIO; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static inline __be32 * xdr_decode_post_op_attr_stream(struct xdr_stream *xdr, struct nfs_fattr *fattr) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; if (ntohl(*p++)) { p = xdr_inline_decode(xdr, 84); if (unlikely(!p)) goto out_overflow; p = xdr_decode_fattr(p, fattr); } return p; out_overflow: print_overflow_msg(__func__, xdr); return ERR_PTR(-EIO); }
__be32 * nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; if (!ntohl(*p++)) { p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; if (!ntohl(*p++)) return ERR_PTR(-EAGAIN); entry->eof = 1; return ERR_PTR(-EBADCOOKIE); } p = xdr_inline_decode(xdr, 8); if (unlikely(!p)) goto out_overflow; entry->ino = ntohl(*p++); entry->len = ntohl(*p++); p = xdr_inline_decode(xdr, entry->len); if (unlikely(!p)) goto out_overflow; entry->name = (const char *) p; p = xdr_inline_decode(xdr, 4); if (unlikely(!p)) goto out_overflow; entry->prev_cookie = entry->cookie; entry->cookie = be32_to_cpup(p); entry->d_type = DT_UNKNOWN; return p; out_overflow: print_overflow_msg(__func__, xdr); return ERR_PTR(-EAGAIN); }
/* * 2.3.5. fattr * * struct fattr { * ftype type; * unsigned int mode; * unsigned int nlink; * unsigned int uid; * unsigned int gid; * unsigned int size; * unsigned int blocksize; * unsigned int rdev; * unsigned int blocks; * unsigned int fsid; * unsigned int fileid; * timeval atime; * timeval mtime; * timeval ctime; * }; * */ static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr) { u32 rdev, type; __be32 *p; p = xdr_inline_decode(xdr, NFS_fattr_sz << 2); if (unlikely(p == NULL)) goto out_overflow; fattr->valid |= NFS_ATTR_FATTR_V2; p = xdr_decode_ftype(p, &type); fattr->mode = be32_to_cpup(p++); fattr->nlink = be32_to_cpup(p++); fattr->uid = be32_to_cpup(p++); fattr->gid = be32_to_cpup(p++); fattr->size = be32_to_cpup(p++); fattr->du.nfs2.blocksize = be32_to_cpup(p++); rdev = be32_to_cpup(p++); fattr->rdev = new_decode_dev(rdev); if (type == (u32)NFCHR && rdev == (u32)NFS2_FIFO_DEV) { fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO; fattr->rdev = 0; } fattr->du.nfs2.blocks = be32_to_cpup(p++); fattr->fsid.major = be32_to_cpup(p++); fattr->fsid.minor = 0; fattr->fileid = be32_to_cpup(p++); p = xdr_decode_time(p, &fattr->atime); p = xdr_decode_time(p, &fattr->mtime); xdr_decode_time(p, &fattr->ctime); fattr->change_attr = nfs_timespec_to_change_attr(&fattr->ctime); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_nlm_stat(struct xdr_stream *xdr, __be32 *stat) { __be32 *p; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) goto out_overflow; if (unlikely(*p > nlm_lck_denied_grace_period)) goto out_enum; *stat = *p; return 0; out_enum: dprintk("%s: server returned invalid nlm_stats value: %u\n", __func__, be32_to_cpup(p)); return -EIO; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_fsstat3resok(struct xdr_stream *xdr, struct nfs_fsstat *result) { __be32 *p; p = xdr_inline_decode(xdr, 8 * 6 + 4); if (unlikely(p == NULL)) goto out_overflow; p = xdr_decode_size3(p, &result->tbytes); p = xdr_decode_size3(p, &result->fbytes); p = xdr_decode_size3(p, &result->abytes); p = xdr_decode_size3(p, &result->tfiles); p = xdr_decode_size3(p, &result->ffiles); xdr_decode_size3(p, &result->afiles); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
/* * CB_COMPOUND4res * * struct CB_COMPOUND4res { * nfsstat4 status; * utf8str_cs tag; * nfs_cb_resop4 resarray<>; * }; */ static int decode_cb_compound4res(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) { u32 length; __be32 *p; p = xdr_inline_decode(xdr, 4 + 4); if (unlikely(p == NULL)) goto out_overflow; hdr->status = be32_to_cpup(p++); /* Ignore the tag */ length = be32_to_cpup(p++); p = xdr_inline_decode(xdr, length + 4); if (unlikely(p == NULL)) goto out_overflow; hdr->nops = be32_to_cpup(p); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_write3resok(struct xdr_stream *xdr, struct nfs_writeres *result) { __be32 *p; p = xdr_inline_decode(xdr, 4 + 4 + NFS3_WRITEVERFSIZE); if (unlikely(p == NULL)) goto out_overflow; result->count = be32_to_cpup(p++); result->verf->committed = be32_to_cpup(p++); if (unlikely(result->verf->committed > NFS_FILE_SYNC)) goto out_badvalue; memcpy(result->verf->verifier, p, NFS3_WRITEVERFSIZE); return result->count; out_badvalue: dprintk("NFS: bad stable_how value: %u\n", result->verf->committed); return -EIO; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_wcc_attr(struct xdr_stream *xdr, struct nfs_fattr *fattr) { __be32 *p; p = xdr_inline_decode(xdr, NFS3_wcc_attr_sz << 2); if (unlikely(p == NULL)) goto out_overflow; fattr->valid |= NFS_ATTR_FATTR_PRESIZE | NFS_ATTR_FATTR_PREMTIME | NFS_ATTR_FATTR_PRECTIME; p = xdr_decode_size3(p, &fattr->pre_size); p = xdr_decode_nfstime3(p, &fattr->pre_mtime); xdr_decode_nfstime3(p, &fattr->pre_ctime); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; }
static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected, enum nfsstat4 *status) { __be32 *p; u32 op; p = xdr_inline_decode(xdr, 4 + 4); if (unlikely(p == NULL)) goto out_overflow; op = be32_to_cpup(p++); if (unlikely(op != expected)) goto out_unexpected; *status = be32_to_cpup(p); return 0; out_overflow: print_overflow_msg(__func__, xdr); return -EIO; out_unexpected: dprintk("NFSD: Callback server returned operation %d but " "we issued a request for %d\n", op, expected); return -EIO; }