2 * Copyright (c) 2008-2010 Sun Microsystems, Inc.
3 * Written by Ricardo Correia <Ricardo.M.Correia@Sun.COM>
5 * This file is part of the SPL, Solaris Porting Layer.
7 * The SPL is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
12 * The SPL is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * You should have received a copy of the GNU General Public License along
18 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
20 * Solaris Porting Layer (SPL) XDR Implementation.
23 #include <linux/string.h>
25 #include <sys/debug.h>
26 #include <sys/types.h>
27 #include <sys/sysmacros.h>
28 #include <rpc/types.h>
32 * SPL's XDR mem implementation.
34 * This is used by libnvpair to serialize/deserialize the name-value pair data
35 * structures into byte arrays in a well-defined and portable manner.
37 * These data structures are used by the DMU/ZFS to flexibly manipulate various
38 * information in memory and later serialize it/deserialize it to disk.
39 * Examples of usages include the pool configuration, lists of pool and dataset
42 * Reference documentation for the XDR representation and XDR operations can be
43 * found in RFC 1832 and xdr(3), respectively.
45 * === Implementation shortcomings ===
47 * It is assumed that the following C types have the following sizes:
49 * char/unsigned char: 1 byte
50 * short/unsigned short: 2 bytes
51 * int/unsigned int: 4 bytes
52 * longlong_t/u_longlong_t: 8 bytes
54 * The C standard allows these types to be larger (and in the case of ints,
55 * shorter), so if that is the case on some compiler/architecture, the build
56 * will fail (on purpose).
58 * If someone wants to fix the code to work properly on such environments, then:
60 * 1) Preconditions should be added to xdrmem_enc functions to make sure the
61 * caller doesn't pass arguments which exceed the expected range.
62 * 2) Functions which take signed integers should be changed to properly do
64 * 3) For ints with less than 32 bits, well.. I suspect you'll have bigger
65 * problems than this implementation.
67 * It is also assumed that:
69 * 1) Chars have 8 bits.
70 * 2) We can always do 32-bit-aligned int memory accesses and byte-aligned
71 * memcpy, memset and memcmp.
72 * 3) Arrays passed to xdr_array() are packed and the compiler/architecture
73 * supports element-sized-aligned memory accesses.
74 * 4) Negative integers are natively stored in two's complement binary
77 * No checks are done for the 4 assumptions above, though.
79 * === Caller expectations ===
81 * Existing documentation does not describe the semantics of XDR operations very
82 * well. Therefore, some assumptions about failure semantics will be made and
83 * will be described below:
85 * 1) If any encoding operation fails (e.g., due to lack of buffer space), the
86 * the stream should be considered valid only up to the encoding operation
87 * previous to the one that first failed. However, the stream size as returned
88 * by xdr_control() cannot be considered to be strictly correct (it may be
91 * Putting it another way, if there is an encoding failure it's undefined
92 * whether anything is added to the stream in that operation and therefore
93 * neither xdr_control() nor future encoding operations on the same stream can
94 * be relied upon to produce correct results.
96 * 2) If a decoding operation fails, it's undefined whether anything will be
97 * decoded into passed buffers/pointers during that operation, or what the
98 * values on those buffers will look like.
100 * Future decoding operations on the same stream will also have similar
101 * undefined behavior.
103 * 3) When the first decoding operation fails it is OK to trust the results of
104 * previous decoding operations on the same stream, as long as the caller
105 * expects a failure to be possible (e.g. due to end-of-stream).
107 * However, this is highly discouraged because the caller should know the
108 * stream size and should be coded to expect any decoding failure to be data
109 * corruption due to hardware, accidental or even malicious causes, which should
110 * be handled gracefully in all cases.
112 * In very rare situations where there are strong reasons to believe the data
113 * can be trusted to be valid and non-tampered with, then the caller may assume
114 * a decoding failure to be a bug (e.g. due to mismatched data types) and may
115 * fail non-gracefully.
117 * 4) Non-zero padding bytes will cause the decoding operation to fail.
119 * 5) Zero bytes on string types will also cause the decoding operation to fail.
121 * 6) It is assumed that either the pointer to the stream buffer given by the
122 * caller is 32-bit aligned or the architecture supports non-32-bit-aligned int
125 * 7) The stream buffer and encoding/decoding buffers/ptrs should not overlap.
127 * 8) If a caller passes pointers to non-kernel memory (e.g., pointers to user
128 * space or MMIO space), the computer may explode.
131 static const struct xdr_ops xdrmem_encode_ops
;
132 static const struct xdr_ops xdrmem_decode_ops
;
135 xdrmem_create(XDR
*xdrs
, const caddr_t addr
, const uint_t size
,
136 const enum xdr_op op
)
140 xdrs
->x_ops
= &xdrmem_encode_ops
;
143 xdrs
->x_ops
= &xdrmem_decode_ops
;
146 xdrs
->x_ops
= NULL
; /* Let the caller know we failed */
152 xdrs
->x_addr_end
= addr
+ size
;
154 if (xdrs
->x_addr_end
< xdrs
->x_addr
) {
158 EXPORT_SYMBOL(xdrmem_create
);
161 xdrmem_control(XDR
*xdrs
, int req
, void *info
)
163 struct xdr_bytesrec
*rec
= (struct xdr_bytesrec
*)info
;
165 if (req
!= XDR_GET_BYTES_AVAIL
)
168 rec
->xc_is_last_record
= TRUE
; /* always TRUE in xdrmem streams */
169 rec
->xc_num_avail
= xdrs
->x_addr_end
- xdrs
->x_addr
;
175 xdrmem_enc_bytes(XDR
*xdrs
, caddr_t cp
, const uint_t cnt
)
177 uint_t size
= roundup(cnt
, 4);
181 return (FALSE
); /* Integer overflow */
183 if (xdrs
->x_addr
> xdrs
->x_addr_end
)
186 if (xdrs
->x_addr_end
- xdrs
->x_addr
< size
)
189 memcpy(xdrs
->x_addr
, cp
, cnt
);
195 memset(xdrs
->x_addr
, 0, pad
);
203 xdrmem_dec_bytes(XDR
*xdrs
, caddr_t cp
, const uint_t cnt
)
205 static uint32_t zero
= 0;
206 uint_t size
= roundup(cnt
, 4);
210 return (FALSE
); /* Integer overflow */
212 if (xdrs
->x_addr
> xdrs
->x_addr_end
)
215 if (xdrs
->x_addr_end
- xdrs
->x_addr
< size
)
218 memcpy(cp
, xdrs
->x_addr
, cnt
);
223 /* An inverted memchr() would be useful here... */
224 if (memcmp(&zero
, xdrs
->x_addr
, pad
) != 0)
234 xdrmem_enc_uint32(XDR
*xdrs
, uint32_t val
)
236 if (xdrs
->x_addr
+ sizeof (uint32_t) > xdrs
->x_addr_end
)
239 *((uint32_t *)xdrs
->x_addr
) = cpu_to_be32(val
);
241 xdrs
->x_addr
+= sizeof (uint32_t);
247 xdrmem_dec_uint32(XDR
*xdrs
, uint32_t *val
)
249 if (xdrs
->x_addr
+ sizeof (uint32_t) > xdrs
->x_addr_end
)
252 *val
= be32_to_cpu(*((uint32_t *)xdrs
->x_addr
));
254 xdrs
->x_addr
+= sizeof (uint32_t);
260 xdrmem_enc_char(XDR
*xdrs
, char *cp
)
264 BUILD_BUG_ON(sizeof (char) != 1);
265 val
= *((unsigned char *) cp
);
267 return (xdrmem_enc_uint32(xdrs
, val
));
271 xdrmem_dec_char(XDR
*xdrs
, char *cp
)
275 BUILD_BUG_ON(sizeof (char) != 1);
277 if (!xdrmem_dec_uint32(xdrs
, &val
))
281 * If any of the 3 other bytes are non-zero then val will be greater
282 * than 0xff and we fail because according to the RFC, this block does
283 * not have a char encoded in it.
288 *((unsigned char *) cp
) = val
;
294 xdrmem_enc_ushort(XDR
*xdrs
, unsigned short *usp
)
296 BUILD_BUG_ON(sizeof (unsigned short) != 2);
298 return (xdrmem_enc_uint32(xdrs
, *usp
));
302 xdrmem_dec_ushort(XDR
*xdrs
, unsigned short *usp
)
306 BUILD_BUG_ON(sizeof (unsigned short) != 2);
308 if (!xdrmem_dec_uint32(xdrs
, &val
))
312 * Short ints are not in the RFC, but we assume similar logic as in
324 xdrmem_enc_uint(XDR
*xdrs
, unsigned *up
)
326 BUILD_BUG_ON(sizeof (unsigned) != 4);
328 return (xdrmem_enc_uint32(xdrs
, *up
));
332 xdrmem_dec_uint(XDR
*xdrs
, unsigned *up
)
334 BUILD_BUG_ON(sizeof (unsigned) != 4);
336 return (xdrmem_dec_uint32(xdrs
, (uint32_t *)up
));
340 xdrmem_enc_ulonglong(XDR
*xdrs
, u_longlong_t
*ullp
)
342 BUILD_BUG_ON(sizeof (u_longlong_t
) != 8);
344 if (!xdrmem_enc_uint32(xdrs
, *ullp
>> 32))
347 return (xdrmem_enc_uint32(xdrs
, *ullp
& 0xffffffff));
351 xdrmem_dec_ulonglong(XDR
*xdrs
, u_longlong_t
*ullp
)
355 BUILD_BUG_ON(sizeof (u_longlong_t
) != 8);
357 if (!xdrmem_dec_uint32(xdrs
, &high
))
359 if (!xdrmem_dec_uint32(xdrs
, &low
))
362 *ullp
= ((u_longlong_t
)high
<< 32) | low
;
368 xdr_enc_array(XDR
*xdrs
, caddr_t
*arrp
, uint_t
*sizep
, const uint_t maxsize
,
369 const uint_t elsize
, const xdrproc_t elproc
)
372 caddr_t addr
= *arrp
;
374 if (*sizep
> maxsize
|| *sizep
> UINT_MAX
/ elsize
)
377 if (!xdrmem_enc_uint(xdrs
, sizep
))
380 for (i
= 0; i
< *sizep
; i
++) {
381 if (!elproc(xdrs
, addr
))
390 xdr_dec_array(XDR
*xdrs
, caddr_t
*arrp
, uint_t
*sizep
, const uint_t maxsize
,
391 const uint_t elsize
, const xdrproc_t elproc
)
394 bool_t alloc
= FALSE
;
397 if (!xdrmem_dec_uint(xdrs
, sizep
))
402 if (size
> maxsize
|| size
> UINT_MAX
/ elsize
)
406 * The Solaris man page says: "If *arrp is NULL when decoding,
407 * xdr_array() allocates memory and *arrp points to it".
410 BUILD_BUG_ON(sizeof (uint_t
) > sizeof (size_t));
412 *arrp
= kmem_alloc(size
* elsize
, KM_NOSLEEP
);
421 for (i
= 0; i
< size
; i
++) {
422 if (!elproc(xdrs
, addr
)) {
424 kmem_free(*arrp
, size
* elsize
);
434 xdr_enc_string(XDR
*xdrs
, char **sp
, const uint_t maxsize
)
436 size_t slen
= strlen(*sp
);
444 if (!xdrmem_enc_uint(xdrs
, &len
))
447 return (xdrmem_enc_bytes(xdrs
, *sp
, len
));
451 xdr_dec_string(XDR
*xdrs
, char **sp
, const uint_t maxsize
)
454 bool_t alloc
= FALSE
;
456 if (!xdrmem_dec_uint(xdrs
, &size
))
459 if (size
> maxsize
|| size
> UINT_MAX
- 1)
463 * Solaris man page: "If *sp is NULL when decoding, xdr_string()
464 * allocates memory and *sp points to it".
467 BUILD_BUG_ON(sizeof (uint_t
) > sizeof (size_t));
469 *sp
= kmem_alloc(size
+ 1, KM_NOSLEEP
);
476 if (!xdrmem_dec_bytes(xdrs
, *sp
, size
))
479 if (memchr(*sp
, 0, size
) != NULL
)
488 kmem_free(*sp
, size
+ 1);
493 static const struct xdr_ops xdrmem_encode_ops
= {
494 .xdr_control
= xdrmem_control
,
495 .xdr_char
= xdrmem_enc_char
,
496 .xdr_u_short
= xdrmem_enc_ushort
,
497 .xdr_u_int
= xdrmem_enc_uint
,
498 .xdr_u_longlong_t
= xdrmem_enc_ulonglong
,
499 .xdr_opaque
= xdrmem_enc_bytes
,
500 .xdr_string
= xdr_enc_string
,
501 .xdr_array
= xdr_enc_array
504 static const struct xdr_ops xdrmem_decode_ops
= {
505 .xdr_control
= xdrmem_control
,
506 .xdr_char
= xdrmem_dec_char
,
507 .xdr_u_short
= xdrmem_dec_ushort
,
508 .xdr_u_int
= xdrmem_dec_uint
,
509 .xdr_u_longlong_t
= xdrmem_dec_ulonglong
,
510 .xdr_opaque
= xdrmem_dec_bytes
,
511 .xdr_string
= xdr_dec_string
,
512 .xdr_array
= xdr_dec_array