]> git.proxmox.com Git - mirror_spl.git/blame - module/spl/spl-xdr.c
Fix more cstyle warnings
[mirror_spl.git] / module / spl / spl-xdr.c
CommitLineData
4b393c50 1/*
716154c5
BB
2 * Copyright (c) 2008-2010 Sun Microsystems, Inc.
3 * Written by Ricardo Correia <Ricardo.M.Correia@Sun.COM>
f48b6193 4 *
716154c5 5 * This file is part of the SPL, Solaris Porting Layer.
3d6af2dd 6 * For details, see <http://zfsonlinux.org/>.
f48b6193 7 *
716154c5
BB
8 * The SPL is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
f48b6193 12 *
716154c5 13 * The SPL is distributed in the hope that it will be useful, but WITHOUT
f48b6193
RC
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
716154c5 19 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
5461eefe 20 *
716154c5 21 * Solaris Porting Layer (SPL) XDR Implementation.
4b393c50 22 */
f48b6193
RC
23
24#include <linux/string.h>
f48b6193
RC
25#include <sys/kmem.h>
26#include <sys/debug.h>
27#include <sys/types.h>
f48b6193
RC
28#include <rpc/types.h>
29#include <rpc/xdr.h>
b17edc10 30
f48b6193
RC
31/*
32 * SPL's XDR mem implementation.
33 *
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.
36 *
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
40 * properties, etc.
41 *
42 * Reference documentation for the XDR representation and XDR operations can be
43 * found in RFC 1832 and xdr(3), respectively.
44 *
45 * === Implementation shortcomings ===
46 *
47 * It is assumed that the following C types have the following sizes:
48 *
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
53 *
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).
57 *
58 * If someone wants to fix the code to work properly on such environments, then:
59 *
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
63 * sign extension.
64 * 3) For ints with less than 32 bits, well.. I suspect you'll have bigger
65 * problems than this implementation.
66 *
67 * It is also assumed that:
68 *
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
75 * representation.
76 *
77 * No checks are done for the 4 assumptions above, though.
78 *
79 * === Caller expectations ===
80 *
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:
84 *
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
89 * bigger).
90 *
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.
95 *
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.
99 *
100 * Future decoding operations on the same stream will also have similar
101 * undefined behavior.
102 *
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).
106 *
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.
111 *
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.
116 *
117 * 4) Non-zero padding bytes will cause the decoding operation to fail.
118 *
119 * 5) Zero bytes on string types will also cause the decoding operation to fail.
120 *
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
123 * memory accesses.
124 *
125 * 7) The stream buffer and encoding/decoding buffers/ptrs should not overlap.
126 *
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.
129 */
130
131static struct xdr_ops xdrmem_encode_ops;
132static struct xdr_ops xdrmem_decode_ops;
133
134void
135xdrmem_create(XDR *xdrs, const caddr_t addr, const uint_t size,
136 const enum xdr_op op)
137{
138 switch (op) {
139 case XDR_ENCODE:
140 xdrs->x_ops = &xdrmem_encode_ops;
141 break;
142 case XDR_DECODE:
143 xdrs->x_ops = &xdrmem_decode_ops;
144 break;
145 default:
f48b6193
RC
146 xdrs->x_ops = NULL; /* Let the caller know we failed */
147 return;
148 }
149
150 xdrs->x_op = op;
151 xdrs->x_addr = addr;
152 xdrs->x_addr_end = addr + size;
153
154 if (xdrs->x_addr_end < xdrs->x_addr) {
f48b6193
RC
155 xdrs->x_ops = NULL;
156 }
157}
158EXPORT_SYMBOL(xdrmem_create);
159
160static bool_t
161xdrmem_control(XDR *xdrs, int req, void *info)
162{
3673d032 163 struct xdr_bytesrec *rec = (struct xdr_bytesrec *)info;
f48b6193 164
8d9a23e8 165 if (req != XDR_GET_BYTES_AVAIL)
5461eefe 166 return (FALSE);
f48b6193
RC
167
168 rec->xc_is_last_record = TRUE; /* always TRUE in xdrmem streams */
169 rec->xc_num_avail = xdrs->x_addr_end - xdrs->x_addr;
170
5461eefe 171 return (TRUE);
f48b6193
RC
172}
173
174static bool_t
175xdrmem_enc_bytes(XDR *xdrs, caddr_t cp, const uint_t cnt)
176{
177 uint_t size = roundup(cnt, 4);
178 uint_t pad;
179
180 if (size < cnt)
5461eefe 181 return (FALSE); /* Integer overflow */
f48b6193
RC
182
183 if (xdrs->x_addr > xdrs->x_addr_end)
5461eefe 184 return (FALSE);
f48b6193 185
6c33eb81 186 if (xdrs->x_addr_end - xdrs->x_addr < size)
5461eefe 187 return (FALSE);
f48b6193
RC
188
189 memcpy(xdrs->x_addr, cp, cnt);
190
191 xdrs->x_addr += cnt;
192
193 pad = size - cnt;
194 if (pad > 0) {
195 memset(xdrs->x_addr, 0, pad);
196 xdrs->x_addr += pad;
197 }
198
5461eefe 199 return (TRUE);
f48b6193
RC
200}
201
202static bool_t
203xdrmem_dec_bytes(XDR *xdrs, caddr_t cp, const uint_t cnt)
204{
205 static uint32_t zero = 0;
206 uint_t size = roundup(cnt, 4);
207 uint_t pad;
208
209 if (size < cnt)
5461eefe 210 return (FALSE); /* Integer overflow */
f48b6193
RC
211
212 if (xdrs->x_addr > xdrs->x_addr_end)
5461eefe 213 return (FALSE);
f48b6193 214
6c33eb81 215 if (xdrs->x_addr_end - xdrs->x_addr < size)
5461eefe 216 return (FALSE);
f48b6193
RC
217
218 memcpy(cp, xdrs->x_addr, cnt);
219 xdrs->x_addr += cnt;
220
221 pad = size - cnt;
222 if (pad > 0) {
223 /* An inverted memchr() would be useful here... */
224 if (memcmp(&zero, xdrs->x_addr, pad) != 0)
5461eefe 225 return (FALSE);
f48b6193
RC
226
227 xdrs->x_addr += pad;
228 }
229
5461eefe 230 return (TRUE);
f48b6193
RC
231}
232
233static bool_t
234xdrmem_enc_uint32(XDR *xdrs, uint32_t val)
235{
5461eefe
BB
236 if (xdrs->x_addr + sizeof (uint32_t) > xdrs->x_addr_end)
237 return (FALSE);
f48b6193 238
3673d032 239 *((uint32_t *)xdrs->x_addr) = cpu_to_be32(val);
f48b6193 240
5461eefe 241 xdrs->x_addr += sizeof (uint32_t);
f48b6193 242
5461eefe 243 return (TRUE);
f48b6193
RC
244}
245
246static bool_t
247xdrmem_dec_uint32(XDR *xdrs, uint32_t *val)
248{
5461eefe
BB
249 if (xdrs->x_addr + sizeof (uint32_t) > xdrs->x_addr_end)
250 return (FALSE);
f48b6193 251
3673d032 252 *val = be32_to_cpu(*((uint32_t *)xdrs->x_addr));
f48b6193 253
5461eefe 254 xdrs->x_addr += sizeof (uint32_t);
f48b6193 255
5461eefe 256 return (TRUE);
f48b6193
RC
257}
258
259static bool_t
260xdrmem_enc_char(XDR *xdrs, char *cp)
261{
262 uint32_t val;
716154c5 263
5461eefe 264 BUILD_BUG_ON(sizeof (char) != 1);
f48b6193
RC
265 val = *((unsigned char *) cp);
266
5461eefe 267 return (xdrmem_enc_uint32(xdrs, val));
f48b6193
RC
268}
269
270static bool_t
271xdrmem_dec_char(XDR *xdrs, char *cp)
272{
273 uint32_t val;
274
5461eefe 275 BUILD_BUG_ON(sizeof (char) != 1);
f48b6193
RC
276
277 if (!xdrmem_dec_uint32(xdrs, &val))
5461eefe 278 return (FALSE);
f48b6193
RC
279
280 /*
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.
284 */
285 if (val > 0xff)
5461eefe 286 return (FALSE);
f48b6193
RC
287
288 *((unsigned char *) cp) = val;
289
5461eefe 290 return (TRUE);
f48b6193
RC
291}
292
293static bool_t
294xdrmem_enc_ushort(XDR *xdrs, unsigned short *usp)
295{
5461eefe 296 BUILD_BUG_ON(sizeof (unsigned short) != 2);
f48b6193 297
5461eefe 298 return (xdrmem_enc_uint32(xdrs, *usp));
f48b6193
RC
299}
300
301static bool_t
302xdrmem_dec_ushort(XDR *xdrs, unsigned short *usp)
303{
304 uint32_t val;
305
5461eefe 306 BUILD_BUG_ON(sizeof (unsigned short) != 2);
f48b6193
RC
307
308 if (!xdrmem_dec_uint32(xdrs, &val))
5461eefe 309 return (FALSE);
f48b6193
RC
310
311 /*
312 * Short ints are not in the RFC, but we assume similar logic as in
313 * xdrmem_dec_char().
314 */
315 if (val > 0xffff)
5461eefe 316 return (FALSE);
f48b6193
RC
317
318 *usp = val;
319
5461eefe 320 return (TRUE);
f48b6193
RC
321}
322
323static bool_t
324xdrmem_enc_uint(XDR *xdrs, unsigned *up)
325{
5461eefe 326 BUILD_BUG_ON(sizeof (unsigned) != 4);
f48b6193 327
5461eefe 328 return (xdrmem_enc_uint32(xdrs, *up));
f48b6193
RC
329}
330
331static bool_t
332xdrmem_dec_uint(XDR *xdrs, unsigned *up)
333{
5461eefe 334 BUILD_BUG_ON(sizeof (unsigned) != 4);
f48b6193 335
3673d032 336 return (xdrmem_dec_uint32(xdrs, (uint32_t *)up));
f48b6193
RC
337}
338
339static bool_t
340xdrmem_enc_ulonglong(XDR *xdrs, u_longlong_t *ullp)
341{
5461eefe 342 BUILD_BUG_ON(sizeof (u_longlong_t) != 8);
f48b6193
RC
343
344 if (!xdrmem_enc_uint32(xdrs, *ullp >> 32))
5461eefe 345 return (FALSE);
f48b6193 346
5461eefe 347 return (xdrmem_enc_uint32(xdrs, *ullp & 0xffffffff));
f48b6193
RC
348}
349
350static bool_t
351xdrmem_dec_ulonglong(XDR *xdrs, u_longlong_t *ullp)
352{
353 uint32_t low, high;
354
5461eefe 355 BUILD_BUG_ON(sizeof (u_longlong_t) != 8);
f48b6193
RC
356
357 if (!xdrmem_dec_uint32(xdrs, &high))
5461eefe 358 return (FALSE);
f48b6193 359 if (!xdrmem_dec_uint32(xdrs, &low))
5461eefe 360 return (FALSE);
f48b6193 361
3673d032 362 *ullp = ((u_longlong_t)high << 32) | low;
f48b6193 363
5461eefe 364 return (TRUE);
f48b6193
RC
365}
366
367static bool_t
368xdr_enc_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep, const uint_t maxsize,
369 const uint_t elsize, const xdrproc_t elproc)
370{
371 uint_t i;
372 caddr_t addr = *arrp;
373
374 if (*sizep > maxsize || *sizep > UINT_MAX / elsize)
5461eefe 375 return (FALSE);
f48b6193
RC
376
377 if (!xdrmem_enc_uint(xdrs, sizep))
5461eefe 378 return (FALSE);
f48b6193
RC
379
380 for (i = 0; i < *sizep; i++) {
381 if (!elproc(xdrs, addr))
5461eefe 382 return (FALSE);
f48b6193
RC
383 addr += elsize;
384 }
385
5461eefe 386 return (TRUE);
f48b6193
RC
387}
388
389static bool_t
390xdr_dec_array(XDR *xdrs, caddr_t *arrp, uint_t *sizep, const uint_t maxsize,
391 const uint_t elsize, const xdrproc_t elproc)
392{
393 uint_t i, size;
394 bool_t alloc = FALSE;
395 caddr_t addr;
396
397 if (!xdrmem_dec_uint(xdrs, sizep))
5461eefe 398 return (FALSE);
f48b6193
RC
399
400 size = *sizep;
401
402 if (size > maxsize || size > UINT_MAX / elsize)
5461eefe 403 return (FALSE);
f48b6193
RC
404
405 /*
406 * The Solaris man page says: "If *arrp is NULL when decoding,
407 * xdr_array() allocates memory and *arrp points to it".
408 */
409 if (*arrp == NULL) {
5461eefe 410 BUILD_BUG_ON(sizeof (uint_t) > sizeof (size_t));
f48b6193
RC
411
412 *arrp = kmem_alloc(size * elsize, KM_NOSLEEP);
413 if (*arrp == NULL)
5461eefe 414 return (FALSE);
f48b6193
RC
415
416 alloc = TRUE;
417 }
418
419 addr = *arrp;
420
421 for (i = 0; i < size; i++) {
422 if (!elproc(xdrs, addr)) {
423 if (alloc)
424 kmem_free(*arrp, size * elsize);
5461eefe 425 return (FALSE);
f48b6193
RC
426 }
427 addr += elsize;
428 }
429
5461eefe 430 return (TRUE);
f48b6193
RC
431}
432
433static bool_t
434xdr_enc_string(XDR *xdrs, char **sp, const uint_t maxsize)
435{
436 size_t slen = strlen(*sp);
437 uint_t len;
438
439 if (slen > maxsize)
5461eefe 440 return (FALSE);
f48b6193
RC
441
442 len = slen;
443
444 if (!xdrmem_enc_uint(xdrs, &len))
5461eefe 445 return (FALSE);
f48b6193 446
5461eefe 447 return (xdrmem_enc_bytes(xdrs, *sp, len));
f48b6193
RC
448}
449
450static bool_t
451xdr_dec_string(XDR *xdrs, char **sp, const uint_t maxsize)
452{
453 uint_t size;
454 bool_t alloc = FALSE;
455
456 if (!xdrmem_dec_uint(xdrs, &size))
5461eefe 457 return (FALSE);
f48b6193
RC
458
459 if (size > maxsize || size > UINT_MAX - 1)
5461eefe 460 return (FALSE);
f48b6193
RC
461
462 /*
463 * Solaris man page: "If *sp is NULL when decoding, xdr_string()
464 * allocates memory and *sp points to it".
465 */
466 if (*sp == NULL) {
5461eefe 467 BUILD_BUG_ON(sizeof (uint_t) > sizeof (size_t));
f48b6193
RC
468
469 *sp = kmem_alloc(size + 1, KM_NOSLEEP);
470 if (*sp == NULL)
5461eefe 471 return (FALSE);
f48b6193
RC
472
473 alloc = TRUE;
474 }
475
476 if (!xdrmem_dec_bytes(xdrs, *sp, size))
477 goto fail;
478
479 if (memchr(*sp, 0, size) != NULL)
480 goto fail;
481
482 (*sp)[size] = '\0';
483
5461eefe 484 return (TRUE);
f48b6193
RC
485
486fail:
487 if (alloc)
488 kmem_free(*sp, size + 1);
489
5461eefe 490 return (FALSE);
f48b6193
RC
491}
492
493static struct xdr_ops xdrmem_encode_ops = {
5461eefe
BB
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
f48b6193
RC
502};
503
504static struct xdr_ops xdrmem_decode_ops = {
5461eefe
BB
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
f48b6193 513};