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