File: /usr/src/linux/net/sunrpc/xdr.c

1     /*
2      * linux/net/sunrpc/xdr.c
3      *
4      * Generic XDR support.
5      *
6      * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7      */
8     
9     #include <linux/types.h>
10     #include <linux/socket.h>
11     #include <linux/string.h>
12     #include <linux/kernel.h>
13     #include <linux/in.h>
14     #include <linux/sunrpc/xdr.h>
15     #include <linux/sunrpc/msg_prot.h>
16     
17     /*
18      * XDR functions for basic NFS types
19      */
20     u32 *
21     xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj)
22     {
23     	unsigned int	quadlen = XDR_QUADLEN(obj->len);
24     
25     	p[quadlen] = 0;		/* zero trailing bytes */
26     	*p++ = htonl(obj->len);
27     	memcpy(p, obj->data, obj->len);
28     	return p + XDR_QUADLEN(obj->len);
29     }
30     
31     u32 *
32     xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len)
33     {
34     	if (ntohl(*p++) != len)
35     		return NULL;
36     	memcpy(obj, p, len);
37     	return p + XDR_QUADLEN(len);
38     }
39     
40     u32 *
41     xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)
42     {
43     	unsigned int	len;
44     
45     	if ((len = ntohl(*p++)) > XDR_MAX_NETOBJ)
46     		return NULL;
47     	obj->len  = len;
48     	obj->data = (u8 *) p;
49     	return p + XDR_QUADLEN(len);
50     }
51     
52     u32 *
53     xdr_encode_array(u32 *p, const char *array, unsigned int len)
54     {
55     	int quadlen = XDR_QUADLEN(len);
56     
57     	p[quadlen] = 0;
58     	*p++ = htonl(len);
59     	memcpy(p, array, len);
60     	return p + quadlen;
61     }
62     
63     u32 *
64     xdr_encode_string(u32 *p, const char *string)
65     {
66     	return xdr_encode_array(p, string, strlen(string));
67     }
68     
69     u32 *
70     xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen)
71     {
72     	unsigned int	len;
73     	char		*string;
74     
75     	if ((len = ntohl(*p++)) > maxlen)
76     		return NULL;
77     	if (lenp)
78     		*lenp = len;
79     	if ((len % 4) != 0) {
80     		string = (char *) p;
81     	} else {
82     		string = (char *) (p - 1);
83     		memmove(string, p, len);
84     	}
85     	string[len] = '\0';
86     	*sp = string;
87     	return p + XDR_QUADLEN(len);
88     }
89     
90     u32 *
91     xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen)
92     {
93     	unsigned int	len;
94     
95     	if ((len = ntohl(*p++)) > maxlen)
96     		return NULL;
97     	*lenp = len;
98     	*sp = p;
99     	return p + XDR_QUADLEN(len);
100     }
101     
102     
103     /*
104      * Realign the iovec if the server missed out some reply elements
105      * (such as post-op attributes,...)
106      * Note: This is a simple implementation that assumes that
107      *            len <= iov->iov_len !!!
108      *       The RPC header (assumed to be the 1st element in the iov array)
109      *            is not shifted.
110      */
111     void xdr_shift_iovec(struct iovec *iov, int nr, size_t len)
112     {
113     	struct iovec *pvec;
114     
115     	for (pvec = iov + nr - 1; nr > 1; nr--, pvec--) {
116     		struct iovec *svec = pvec - 1;
117     
118     		if (len > pvec->iov_len) {
119     			printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
120     			return;
121     		}
122     		memmove((char *)pvec->iov_base + len, pvec->iov_base,
123     			pvec->iov_len - len);
124     
125     		if (len > svec->iov_len) {
126     			printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
127     			return;
128     		}
129     		memcpy(pvec->iov_base,
130     		       (char *)svec->iov_base + svec->iov_len - len, len);
131     	}
132     }
133     
134     /*
135      * Zero the last n bytes in an iovec array of 'nr' elements
136      */
137     void xdr_zero_iovec(struct iovec *iov, int nr, size_t n)
138     {
139     	struct iovec *pvec;
140     
141     	for (pvec = iov + nr - 1; n && nr > 0; nr--, pvec--) {
142     		if (n < pvec->iov_len) {
143     			memset((char *)pvec->iov_base + pvec->iov_len - n, 0, n);
144     			n = 0;
145     		} else {
146     			memset(pvec->iov_base, 0, pvec->iov_len);
147     			n -= pvec->iov_len;
148     		}
149     	}
150     }
151