1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
32 */
33
34 /*
35 * xdr.c, generic XDR routines implementation.
36 * These are the "generic" xdr routines used to serialize and de-serialize
37 * most common data items. See xdr.h for more info on the interface to
38 * xdr.
39 */
40
41 #include <sys/param.h>
42 #include <sys/cmn_err.h>
43 #include <sys/types.h>
44 #include <sys/systm.h>
45
46 #include <rpc/types.h>
47 #include <rpc/xdr.h>
48 #include <sys/isa_defs.h>
49
50 #pragma weak xdr_int32_t = xdr_int
51 #pragma weak xdr_uint32_t = xdr_u_int
52 #pragma weak xdr_int64_t = xdr_longlong_t
53 #pragma weak xdr_uint64_t = xdr_u_longlong_t
54
55 #if !defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
56 #error "Exactly one of _BIG_ENDIAN or _LITTLE_ENDIAN must be defined"
57 #elif defined(_BIG_ENDIAN) && defined(_LITTLE_ENDIAN)
58 #error "Only one of _BIG_ENDIAN or _LITTLE_ENDIAN may be defined"
59 #endif
60
61 /*
62 * constants specific to the xdr "protocol"
63 */
64 #define XDR_FALSE ((int32_t)0)
65 #define XDR_TRUE ((int32_t)1)
66 #define LASTUNSIGNED ((uint_t)0-1)
67
68 /*
69 * for unit alignment
70 */
71 static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
72
73 /*
74 * Free a data structure using XDR
75 * Not a filter, but a convenient utility nonetheless
76 */
77 void
xdr_free(xdrproc_t proc,char * objp)78 xdr_free(xdrproc_t proc, char *objp)
79 {
80 XDR x;
81
82 x.x_op = XDR_FREE;
83 (*proc)(&x, objp);
84 }
85
86 /*
87 * XDR nothing
88 */
89 bool_t
xdr_void(void)90 xdr_void(void)
91 {
92 return (TRUE);
93 }
94
95 /*
96 * XDR integers
97 *
98 * PSARC 2003/523 Contract Private Interface
99 * xdr_int
100 * Changes must be reviewed by Solaris File Sharing
101 * Changes must be communicated to contract-2003-523@sun.com
102 */
103 bool_t
xdr_int(XDR * xdrs,int * ip)104 xdr_int(XDR *xdrs, int *ip)
105 {
106 if (xdrs->x_op == XDR_ENCODE)
107 return (XDR_PUTINT32(xdrs, ip));
108
109 if (xdrs->x_op == XDR_DECODE)
110 return (XDR_GETINT32(xdrs, ip));
111
112 if (xdrs->x_op == XDR_FREE)
113 return (TRUE);
114
115 return (FALSE);
116 }
117
118 /*
119 * XDR unsigned integers
120 *
121 * PSARC 2003/523 Contract Private Interface
122 * xdr_u_int
123 * Changes must be reviewed by Solaris File Sharing
124 * Changes must be communicated to contract-2003-523@sun.com
125 */
126 bool_t
xdr_u_int(XDR * xdrs,uint_t * up)127 xdr_u_int(XDR *xdrs, uint_t *up)
128 {
129 if (xdrs->x_op == XDR_ENCODE)
130 return (XDR_PUTINT32(xdrs, (int32_t *)up));
131
132 if (xdrs->x_op == XDR_DECODE)
133 return (XDR_GETINT32(xdrs, (int32_t *)up));
134
135 if (xdrs->x_op == XDR_FREE)
136 return (TRUE);
137
138 return (FALSE);
139 }
140
141
142 #if defined(_ILP32)
143 /*
144 * xdr_long and xdr_u_long for binary compatability on ILP32 kernels.
145 *
146 * No prototypes since new code should not be using these interfaces.
147 */
148 bool_t
xdr_long(XDR * xdrs,long * ip)149 xdr_long(XDR *xdrs, long *ip)
150 {
151 return (xdr_int(xdrs, (int *)ip));
152 }
153
154 bool_t
xdr_u_long(XDR * xdrs,unsigned long * up)155 xdr_u_long(XDR *xdrs, unsigned long *up)
156 {
157 return (xdr_u_int(xdrs, (uint_t *)up));
158 }
159 #endif /* _ILP32 */
160
161
162 /*
163 * XDR long long integers
164 */
165 bool_t
xdr_longlong_t(XDR * xdrs,longlong_t * hp)166 xdr_longlong_t(XDR *xdrs, longlong_t *hp)
167 {
168 if (xdrs->x_op == XDR_ENCODE) {
169 #if defined(_LITTLE_ENDIAN)
170 if (XDR_PUTINT32(xdrs, (int32_t *)((char *)hp +
171 BYTES_PER_XDR_UNIT)) == TRUE) {
172 return (XDR_PUTINT32(xdrs, (int32_t *)hp));
173 }
174 #elif defined(_BIG_ENDIAN)
175 if (XDR_PUTINT32(xdrs, (int32_t *)hp) == TRUE) {
176 return (XDR_PUTINT32(xdrs, (int32_t *)((char *)hp +
177 BYTES_PER_XDR_UNIT)));
178 }
179 #endif
180 return (FALSE);
181
182 }
183 if (xdrs->x_op == XDR_DECODE) {
184 #if defined(_LITTLE_ENDIAN)
185 if (XDR_GETINT32(xdrs, (int32_t *)((char *)hp +
186 BYTES_PER_XDR_UNIT)) == TRUE) {
187 return (XDR_GETINT32(xdrs, (int32_t *)hp));
188 }
189 #elif defined(_BIG_ENDIAN)
190 if (XDR_GETINT32(xdrs, (int32_t *)hp) == TRUE) {
191 return (XDR_GETINT32(xdrs, (int32_t *)((char *)hp +
192 BYTES_PER_XDR_UNIT)));
193 }
194 #endif
195 return (FALSE);
196 }
197 return (TRUE);
198 }
199
200 /*
201 * XDR unsigned long long integers
202 */
203 bool_t
xdr_u_longlong_t(XDR * xdrs,u_longlong_t * hp)204 xdr_u_longlong_t(XDR *xdrs, u_longlong_t *hp)
205 {
206
207 if (xdrs->x_op == XDR_ENCODE) {
208 #if defined(_LITTLE_ENDIAN)
209 if (XDR_PUTINT32(xdrs, (int32_t *)((char *)hp +
210 BYTES_PER_XDR_UNIT)) == TRUE) {
211 return (XDR_PUTINT32(xdrs, (int32_t *)hp));
212 }
213 #elif defined(_BIG_ENDIAN)
214 if (XDR_PUTINT32(xdrs, (int32_t *)hp) == TRUE) {
215 return (XDR_PUTINT32(xdrs, (int32_t *)((char *)hp +
216 BYTES_PER_XDR_UNIT)));
217 }
218 #endif
219 return (FALSE);
220
221 }
222 if (xdrs->x_op == XDR_DECODE) {
223 #if defined(_LITTLE_ENDIAN)
224 if (XDR_GETINT32(xdrs, (int32_t *)((char *)hp +
225 BYTES_PER_XDR_UNIT)) == TRUE) {
226 return (XDR_GETINT32(xdrs, (int32_t *)hp));
227 }
228 #elif defined(_BIG_ENDIAN)
229 if (XDR_GETINT32(xdrs, (int32_t *)hp) == TRUE) {
230 return (XDR_GETINT32(xdrs, (int32_t *)((char *)hp +
231 BYTES_PER_XDR_UNIT)));
232 }
233 #endif
234 return (FALSE);
235 }
236 return (TRUE);
237 }
238
239 /*
240 * XDR short integers
241 */
242 bool_t
xdr_short(XDR * xdrs,short * sp)243 xdr_short(XDR *xdrs, short *sp)
244 {
245 int32_t l;
246
247 switch (xdrs->x_op) {
248
249 case XDR_ENCODE:
250 l = (int32_t)*sp;
251 return (XDR_PUTINT32(xdrs, &l));
252
253 case XDR_DECODE:
254 if (!XDR_GETINT32(xdrs, &l))
255 return (FALSE);
256 *sp = (short)l;
257 return (TRUE);
258
259 case XDR_FREE:
260 return (TRUE);
261 }
262 return (FALSE);
263 }
264
265 /*
266 * XDR unsigned short integers
267 */
268 bool_t
xdr_u_short(XDR * xdrs,ushort_t * usp)269 xdr_u_short(XDR *xdrs, ushort_t *usp)
270 {
271 uint32_t l;
272
273 switch (xdrs->x_op) {
274
275 case XDR_ENCODE:
276 l = (uint32_t)*usp;
277 return (XDR_PUTINT32(xdrs, (int32_t *)&l));
278
279 case XDR_DECODE:
280 if (!XDR_GETINT32(xdrs, (int32_t *)&l)) {
281 return (FALSE);
282 }
283 *usp = (ushort_t)l;
284 return (TRUE);
285
286 case XDR_FREE:
287 return (TRUE);
288 }
289 return (FALSE);
290 }
291
292
293 /*
294 * XDR a char
295 */
296 bool_t
xdr_char(XDR * xdrs,char * cp)297 xdr_char(XDR *xdrs, char *cp)
298 {
299 int i;
300
301 i = (*cp);
302 if (!xdr_int(xdrs, &i)) {
303 return (FALSE);
304 }
305 *cp = (char)i;
306 return (TRUE);
307 }
308
309 /*
310 * XDR an unsigned char
311 */
312 bool_t
xdr_u_char(XDR * xdrs,uchar_t * cp)313 xdr_u_char(XDR *xdrs, uchar_t *cp)
314 {
315 int i;
316
317 switch (xdrs->x_op) {
318 case XDR_ENCODE:
319 i = (*cp);
320 return (XDR_PUTINT32(xdrs, &i));
321 case XDR_DECODE:
322 if (!XDR_GETINT32(xdrs, &i))
323 return (FALSE);
324 *cp = (uchar_t)i;
325 return (TRUE);
326 case XDR_FREE:
327 return (TRUE);
328 }
329 return (FALSE);
330 }
331
332 /*
333 * XDR booleans
334 *
335 * PSARC 2003/523 Contract Private Interface
336 * xdr_bool
337 * Changes must be reviewed by Solaris File Sharing
338 * Changes must be communicated to contract-2003-523@sun.com
339 */
340 bool_t
xdr_bool(XDR * xdrs,bool_t * bp)341 xdr_bool(XDR *xdrs, bool_t *bp)
342 {
343 int32_t i32b;
344
345 switch (xdrs->x_op) {
346
347 case XDR_ENCODE:
348 i32b = *bp ? XDR_TRUE : XDR_FALSE;
349 return (XDR_PUTINT32(xdrs, &i32b));
350
351 case XDR_DECODE:
352 if (!XDR_GETINT32(xdrs, &i32b)) {
353 return (FALSE);
354 }
355 *bp = (i32b == XDR_FALSE) ? FALSE : TRUE;
356 return (TRUE);
357
358 case XDR_FREE:
359 return (TRUE);
360 }
361 return (FALSE);
362 }
363
364 /*
365 * XDR enumerations
366 *
367 * PSARC 2003/523 Contract Private Interface
368 * xdr_enum
369 * Changes must be reviewed by Solaris File Sharing
370 * Changes must be communicated to contract-2003-523@sun.com
371 */
372 #ifndef lint
373 enum sizecheck { SIZEVAL } sizecheckvar; /* used to find the size of */
374 /* an enum */
375 #endif
376 bool_t
xdr_enum(XDR * xdrs,enum_t * ep)377 xdr_enum(XDR *xdrs, enum_t *ep)
378 {
379 #ifndef lint
380 /*
381 * enums are treated as ints
382 */
383 if (sizeof (sizecheckvar) == sizeof (int32_t)) {
384 return (xdr_int(xdrs, (int32_t *)ep));
385 } else if (sizeof (sizecheckvar) == sizeof (short)) {
386 return (xdr_short(xdrs, (short *)ep));
387 } else {
388 return (FALSE);
389 }
390 #else
391 (void) (xdr_short(xdrs, (short *)ep));
392 return (xdr_int(xdrs, (int32_t *)ep));
393 #endif
394 }
395
396 /*
397 * XDR opaque data
398 * Allows the specification of a fixed size sequence of opaque bytes.
399 * cp points to the opaque object and cnt gives the byte length.
400 *
401 * PSARC 2003/523 Contract Private Interface
402 * xdr_opaque
403 * Changes must be reviewed by Solaris File Sharing
404 * Changes must be communicated to contract-2003-523@sun.com
405 */
406 bool_t
xdr_opaque(XDR * xdrs,caddr_t cp,const uint_t cnt)407 xdr_opaque(XDR *xdrs, caddr_t cp, const uint_t cnt)
408 {
409 uint_t rndup;
410 static char crud[BYTES_PER_XDR_UNIT];
411
412 /*
413 * if no data we are done
414 */
415 if (cnt == 0)
416 return (TRUE);
417
418 /*
419 * round byte count to full xdr units
420 */
421 rndup = cnt % BYTES_PER_XDR_UNIT;
422 if (rndup != 0)
423 rndup = BYTES_PER_XDR_UNIT - rndup;
424
425 if (xdrs->x_op == XDR_DECODE) {
426 if (!XDR_GETBYTES(xdrs, cp, cnt)) {
427 return (FALSE);
428 }
429 if (rndup == 0)
430 return (TRUE);
431 return (XDR_GETBYTES(xdrs, (caddr_t)crud, rndup));
432 }
433
434 if (xdrs->x_op == XDR_ENCODE) {
435 if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
436 return (FALSE);
437 }
438 if (rndup == 0)
439 return (TRUE);
440 return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
441 }
442
443 if (xdrs->x_op == XDR_FREE)
444 return (TRUE);
445
446 return (FALSE);
447 }
448
449 /*
450 * XDR counted bytes
451 * *cpp is a pointer to the bytes, *sizep is the count.
452 * If *cpp is NULL maxsize bytes are allocated
453 *
454 * PSARC 2003/523 Contract Private Interface
455 * xdr_bytes
456 * Changes must be reviewed by Solaris File Sharing
457 * Changes must be communicated to contract-2003-523@sun.com
458 */
459 bool_t
xdr_bytes(XDR * xdrs,char ** cpp,uint_t * sizep,const uint_t maxsize)460 xdr_bytes(XDR *xdrs, char **cpp, uint_t *sizep, const uint_t maxsize)
461 {
462 char *sp = *cpp; /* sp is the actual string pointer */
463 uint_t nodesize;
464
465 /*
466 * first deal with the length since xdr bytes are counted
467 */
468 if (!xdr_u_int(xdrs, sizep)) {
469 return (FALSE);
470 }
471 nodesize = *sizep;
472 if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
473 return (FALSE);
474 }
475
476 /*
477 * now deal with the actual bytes
478 */
479 switch (xdrs->x_op) {
480 case XDR_DECODE:
481 if (nodesize == 0)
482 return (TRUE);
483 if (sp == NULL)
484 *cpp = sp = (char *)mem_alloc(nodesize);
485 /* FALLTHROUGH */
486
487 case XDR_ENCODE:
488 return (xdr_opaque(xdrs, sp, nodesize));
489
490 case XDR_FREE:
491 if (sp != NULL) {
492 mem_free(sp, nodesize);
493 *cpp = NULL;
494 }
495 return (TRUE);
496 }
497 return (FALSE);
498 }
499
500 /*
501 * Implemented here due to commonality of the object.
502 */
503 bool_t
xdr_netobj(XDR * xdrs,struct netobj * np)504 xdr_netobj(XDR *xdrs, struct netobj *np)
505 {
506 return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
507 }
508
509 /*
510 * XDR a descriminated union
511 * Support routine for discriminated unions.
512 * You create an array of xdrdiscrim structures, terminated with
513 * an entry with a null procedure pointer. The routine gets
514 * the discriminant value and then searches the array of xdrdiscrims
515 * looking for that value. It calls the procedure given in the xdrdiscrim
516 * to handle the discriminant. If there is no specific routine a default
517 * routine may be called.
518 * If there is no specific or default routine an error is returned.
519 */
520 bool_t
xdr_union(XDR * xdrs,enum_t * dscmp,char * unp,const struct xdr_discrim * choices,const xdrproc_t dfault)521 xdr_union(XDR *xdrs, enum_t *dscmp, char *unp,
522 const struct xdr_discrim *choices, const xdrproc_t dfault)
523 {
524 enum_t dscm;
525
526 /*
527 * we deal with the discriminator; it's an enum
528 */
529 if (!xdr_enum(xdrs, dscmp)) {
530 return (FALSE);
531 }
532 dscm = *dscmp;
533
534 /*
535 * search choices for a value that matches the discriminator.
536 * if we find one, execute the xdr routine for that value.
537 */
538 for (; choices->proc != NULL_xdrproc_t; choices++) {
539 if (choices->value == dscm)
540 return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED));
541 }
542
543 /*
544 * no match - execute the default xdr routine if there is one
545 */
546 return ((dfault == NULL_xdrproc_t) ? FALSE :
547 (*dfault)(xdrs, unp, LASTUNSIGNED));
548 }
549
550
551 /*
552 * Non-portable xdr primitives.
553 * Care should be taken when moving these routines to new architectures.
554 */
555
556
557 /*
558 * XDR null terminated ASCII strings
559 * xdr_string deals with "C strings" - arrays of bytes that are
560 * terminated by a NULL character. The parameter cpp references a
561 * pointer to storage; If the pointer is null, then the necessary
562 * storage is allocated. The last parameter is the max allowed length
563 * of the string as specified by a protocol.
564 */
565 bool_t
xdr_string(XDR * xdrs,char ** cpp,const uint_t maxsize)566 xdr_string(XDR *xdrs, char **cpp, const uint_t maxsize)
567 {
568 char *sp = *cpp; /* sp is the actual string pointer */
569 uint_t size;
570 uint_t nodesize;
571
572 /*
573 * first deal with the length since xdr strings are counted-strings
574 */
575 switch (xdrs->x_op) {
576 case XDR_FREE:
577 if (sp == NULL)
578 return (TRUE); /* already free */
579 /* FALLTHROUGH */
580 case XDR_ENCODE:
581 size = (sp != NULL) ? (uint_t)strlen(sp) : 0;
582 break;
583 case XDR_DECODE:
584 break;
585 }
586 if (!xdr_u_int(xdrs, &size)) {
587 return (FALSE);
588 }
589 if (size > maxsize) {
590 return (FALSE);
591 }
592 nodesize = size + 1;
593
594 /*
595 * now deal with the actual bytes
596 */
597 switch (xdrs->x_op) {
598 case XDR_DECODE:
599 if (nodesize == 0)
600 return (TRUE);
601 if (sp == NULL)
602 sp = (char *)mem_alloc(nodesize);
603 sp[size] = 0;
604 if (!xdr_opaque(xdrs, sp, size)) {
605 /*
606 * free up memory if allocated here
607 */
608 if (*cpp == NULL) {
609 mem_free(sp, nodesize);
610 }
611 return (FALSE);
612 }
613 if (strlen(sp) != size) {
614 if (*cpp == NULL) {
615 mem_free(sp, nodesize);
616 }
617 return (FALSE);
618 }
619 *cpp = sp;
620 return (TRUE);
621
622 case XDR_ENCODE:
623 return (xdr_opaque(xdrs, sp, size));
624
625 case XDR_FREE:
626 mem_free(sp, nodesize);
627 *cpp = NULL;
628 return (TRUE);
629 }
630 return (FALSE);
631 }
632
633 /*
634 * xdr_vector():
635 *
636 * XDR a fixed length array. Unlike variable-length arrays, the storage
637 * of fixed length arrays is static and unfreeable.
638 * > basep: base of the array
639 * > size: size of the array
640 * > elemsize: size of each element
641 * > xdr_elem: routine to XDR each element
642 */
643 bool_t
xdr_vector(XDR * xdrs,char * basep,const uint_t nelem,const uint_t elemsize,const xdrproc_t xdr_elem)644 xdr_vector(XDR *xdrs, char *basep, const uint_t nelem,
645 const uint_t elemsize, const xdrproc_t xdr_elem)
646 {
647 uint_t i;
648 char *elptr;
649
650 elptr = basep;
651 for (i = 0; i < nelem; i++) {
652 if (!(*xdr_elem)(xdrs, elptr, LASTUNSIGNED))
653 return (FALSE);
654 elptr += elemsize;
655 }
656 return (TRUE);
657 }
658
659 /*
660 * Wrapper for xdr_string that can be called directly from
661 * routines like clnt_call
662 */
663 bool_t
xdr_wrapstring(XDR * xdrs,char ** cpp)664 xdr_wrapstring(XDR *xdrs, char **cpp)
665 {
666 if (xdr_string(xdrs, cpp, LASTUNSIGNED))
667 return (TRUE);
668 return (FALSE);
669 }
670