/*
* linux/net/sunrpc/xdr.c
*
* Generic XDR support.
*
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
#include <linux/errno.h>
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/msg_prot.h>
/*
* XDR functions for basic NFS types
*/
__be32 *
xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj)
{
unsigned int quadlen = XDR_QUADLEN(obj->len);
p[quadlen] = 0; /* zero trailing bytes */
*p++ = htonl(obj->len);
memcpy(p, obj->data, obj->len);
return p + XDR_QUADLEN(obj->len);
}
__be32 *
xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj)
{
unsigned int len;
if ((len = ntohl(*p++)) > XDR_MAX_NETOBJ)
return NULL;
obj->len = len;
obj->data = (u8 *) p;
return p + XDR_QUADLEN(len);
}
/**
* xdr_encode_opaque_fixed - Encode fixed length opaque data
* @p: pointer to current position in XDR buffer.
* @ptr: pointer to data to encode (or NULL)
* @nbytes: size of data.
*
* Copy the array of data of length nbytes at ptr to the XDR buffer
* at position p, then align to the next 32-bit boundary by padding
* with zero bytes (see RFC1832).
* Note: if ptr is NULL, only the padding is performed.
*
* Returns the updated current XDR buffer position
*
*/
__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int nbytes)
{
if (likely(nbytes != 0)) {
unsigned int quadlen = XDR_QUADLEN(nbytes);
unsigned int padding = (quadlen << 2) - nbytes;
if (ptr != NULL)
memcpy(p, ptr, nbytes);
if (padding != 0)
memset((char *)p + nbytes, 0, padding);
p += quadlen;
}
return p;
}
EXPORT_SYMBOL(xdr_encode_opaque_fixed);
/**
* xdr_encode_opaque - Encode variable length opaque data
* @p: pointer to current position in XDR buffer.
* @ptr: pointer to data to encode (or NULL)
* @nbytes: size of data.
*
* Returns the updated current XDR buffer position
*/
__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int nbytes)
{
*p++ = htonl(nbytes);
return xdr_encode_opaque_fixed(p, ptr, nbytes);
}
EXPORT_SYMBOL(xdr_encode_opaque);
__be32 *
xdr_encode_string(__be32 *p, const char *string)
{
return xdr_encode_array(p, string, strlen(string));
}
__be32 *
xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen)
{
unsigned int len;
if ((len = ntohl(*p++)) > maxlen)
return NULL;
*lenp = len;
*sp = (char *) p;
return p + XDR_QUADLEN(len);
}
void
xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base,
unsigned int len)
{
struct kvec *tail = xdr->tail;
u32 *p;
xdr->pages = pages;
xdr->page_base = base;
xdr->page_len = len;
p = (u32 *)xdr->head[0].iov_base + XDR_QUADLEN(xdr->head[0].iov_len);
tail->iov_base = p;
tail->iov_len = 0;
if (len & 3) {
unsigned int pad = 4 - (len & 3);
*p = 0;
tail->iov_base = (char *)p + (len & 3);
tail->iov_len = pad;
len += pad;
}
xdr->buflen += len;
xdr->len += len;
}
void
xdr_inline_pages(struct xdr_buf *xdr, unsigned int offset,
struct page **pages, unsigned int base, unsigned int len)
{
struct