xref: /titanic_51/usr/src/lib/libnsl/rpc/xdr.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
26 /* All Rights Reserved */
27 /*
28  * Portions of this source code were derived from Berkeley
29  * 4.3 BSD under license from the Regents of the University of
30  * California.
31  */
32 
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 
35 /*
36  * xdr.c, Generic XDR routines implementation.
37  *
38  * These are the "generic" xdr routines used to serialize and de-serialize
39  * most common data items.  See xdr.h for more info on the interface to
40  * xdr.
41  */
42 #include <sys/types.h>
43 #include <sys/isa_defs.h>
44 #include <rpc/trace.h>
45 
46 #ifdef KERNEL
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #else
50 #include <syslog.h>
51 #include <stdio.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #endif
55 
56 #include <limits.h>
57 #include <rpc/types.h>
58 #include <rpc/xdr.h>
59 #include <inttypes.h>
60 #include <sys/sysmacros.h>
61 
62 #pragma weak xdr_int64_t = xdr_hyper
63 #pragma weak xdr_uint64_t = xdr_u_hyper
64 #pragma weak xdr_int32_t = xdr_int
65 #pragma weak xdr_uint32_t = xdr_u_int
66 #pragma weak xdr_int16_t = xdr_short
67 #pragma weak xdr_uint16_t = xdr_u_short
68 #pragma weak xdr_int8_t = xdr_char
69 #pragma weak xdr_uint8_t = xdr_u_char
70 
71 /*
72  * constants specific to the xdr "protocol"
73  */
74 #define	XDR_FALSE	((uint_t)0)
75 #define	XDR_TRUE	((uint_t)1)
76 #define	LASTUNSIGNED	((uint_t)0-1)
77 
78 /* fragment size to use when doing an xdr_string() */
79 #define	FRAGMENT	65536
80 
81 /*
82  * for unit alignment
83  */
84 static const char xdr_zero[BYTES_PER_XDR_UNIT]	= { 0 };
85 
86 #ifndef KERNEL
87 /*
88  * Free a data structure using XDR
89  * Not a filter, but a convenient utility nonetheless
90  */
91 void
92 xdr_free(xdrproc_t proc, char *objp)
93 {
94 	XDR x;
95 
96 	trace1(TR_xdr_free, 0);
97 	x.x_op = XDR_FREE;
98 	(*proc)(&x, objp);
99 	trace1(TR_xdr_free, 1);
100 }
101 #endif
102 
103 /*
104  * XDR nothing
105  */
106 bool_t
107 xdr_void()
108 {
109 	trace1(TR_xdr_void, 0);
110 	trace1(TR_xdr_void, 1);
111 	return (TRUE);
112 }
113 
114 /*
115  * xdr_time_t  sends time_t value over the wire.
116  * Due to RPC Protocol limitation, it can only send
117  * up to 32-bit integer quantity over the wire.
118  *
119  */
120 bool_t
121 xdr_time_t(XDR *xdrs, time_t *tp)
122 {
123 	bool_t dummy;
124 	int32_t i;
125 
126 	trace1(TR_xdr_time_t, 0);
127 	switch (xdrs->x_op) {
128 	case XDR_ENCODE:
129 	/*
130 	 * Check for the time overflow, when encoding it.
131 	 * Don't want to send OTW the time value too large to
132 	 * handle by the protocol.
133 	 */
134 #if defined(_LP64)
135 	if (*tp > INT32_MAX)
136 		*tp = INT32_MAX;
137 	else if (*tp < INT32_MIN)
138 		*tp = INT32_MIN;
139 #endif
140 		i =  (int32_t)*tp;
141 		dummy = XDR_PUTINT32(xdrs, &i);
142 		trace1(TR_xdr_time_t, 1);
143 		return (dummy);
144 
145 	case XDR_DECODE:
146 		if (!XDR_GETINT32(xdrs, &i)) {
147 			trace1(TR_xdr_time_t, 1);
148 			return (FALSE);
149 		}
150 		*tp = (time_t)i;
151 		trace1(TR_xdr_time_t, 1);
152 		return (TRUE);
153 
154 	case XDR_FREE:
155 		trace1(TR_xdr_time_t, 1);
156 		return (TRUE);
157 	}
158 	trace1(TR_xdr_time_t, 1);
159 	return (FALSE);
160 }
161 
162 /*
163  * XDR integers
164  */
165 bool_t
166 xdr_int(XDR *xdrs, int *ip)
167 {
168 	trace1(TR_xdr_int, 0);
169 	if (xdrs->x_op == XDR_ENCODE)
170 		return (XDR_PUTINT32(xdrs, ip));
171 
172 	if (xdrs->x_op == XDR_DECODE)
173 		return (XDR_GETINT32(xdrs, ip));
174 
175 	if (xdrs->x_op == XDR_FREE)
176 		return (TRUE);
177 
178 	trace1(TR_xdr_int, 1);
179 	return (FALSE);
180 }
181 
182 /*
183  * XDR unsigned integers
184  */
185 bool_t
186 xdr_u_int(XDR *xdrs, uint_t *up)
187 {
188 	trace1(TR_xdr_u_int, 0);
189 	if (xdrs->x_op == XDR_ENCODE)
190 		return (XDR_PUTINT32(xdrs, (int *)up));
191 
192 	if (xdrs->x_op == XDR_DECODE)
193 		return (XDR_GETINT32(xdrs, (int *)up));
194 
195 	if (xdrs->x_op == XDR_FREE)
196 		return (TRUE);
197 
198 	trace1(TR_xdr_u_int, 1);
199 	return (FALSE);
200 }
201 
202 #ifndef KERNEL
203 static const char xdrlong_err[] =
204 			"xdr_%s: value too large to be stored in data type";
205 #endif
206 
207 /*
208  * The definition of xdr_long()/xdr_u_long() is kept for backward
209  * compatibitlity.
210  * XDR long integers, same as xdr_u_long
211  */
212 
213 bool_t
214 xdr_long(XDR *xdrs, long *lp)
215 {
216 	bool_t dummy;
217 	int32_t i;
218 
219 	trace1(TR_xdr_long, 0);
220 	if (xdrs->x_op == XDR_ENCODE) {
221 #if defined(_LP64)
222 		if ((*lp > INT32_MAX) || (*lp < INT32_MIN)) {
223 			return (FALSE);
224 		}
225 #endif
226 		i = (int32_t)*lp;
227 		dummy = XDR_PUTINT32(xdrs, &i);
228 	} else if (xdrs->x_op == XDR_DECODE) {
229 		dummy = XDR_GETINT32(xdrs, &i);
230 		*lp = (long)i;
231 	} else if (xdrs->x_op == XDR_FREE)
232 		dummy = TRUE;
233 	else
234 		dummy = FALSE;
235 	trace1(TR_xdr_long, 1);
236 	return (dummy);
237 }
238 
239 /*
240  * XDR unsigned long integers
241  * same as xdr_long
242  */
243 bool_t
244 xdr_u_long(XDR *xdrs, ulong_t *ulp)
245 {
246 	bool_t dummy;
247 	uint32_t ui;
248 
249 	trace1(TR_xdr_u_long, 0);
250 	if (xdrs->x_op == XDR_ENCODE) {
251 #if defined(_LP64)
252 		if (*ulp > UINT32_MAX) {
253 			return (FALSE);
254 		}
255 #endif
256 		ui = (uint32_t)*ulp;
257 		dummy = XDR_PUTINT32(xdrs, (int32_t *)&ui);
258 	} else if (xdrs->x_op == XDR_DECODE) {
259 		dummy = XDR_GETINT32(xdrs, (int32_t *)&ui);
260 		*ulp = (ulong_t)ui;
261 	} else if (xdrs->x_op == XDR_FREE)
262 		dummy = TRUE;
263 	else
264 		dummy = FALSE;
265 	trace1(TR_xdr_u_long, 1);
266 	return (dummy);
267 }
268 
269 /*
270  * XDR short integers
271  */
272 bool_t
273 xdr_short(XDR *xdrs, short *sp)
274 {
275 	int32_t l;
276 	bool_t dummy;
277 
278 	trace1(TR_xdr_short, 0);
279 	switch (xdrs->x_op) {
280 
281 	case XDR_ENCODE:
282 		l = (int32_t)*sp;
283 		dummy = XDR_PUTINT32(xdrs, &l);
284 		trace1(TR_xdr_short, 1);
285 		return (dummy);
286 
287 	case XDR_DECODE:
288 		if (!XDR_GETINT32(xdrs, &l)) {
289 			trace1(TR_xdr_short, 1);
290 			return (FALSE);
291 		}
292 		*sp = (short)l;
293 		trace1(TR_xdr_short, 1);
294 		return (TRUE);
295 
296 	case XDR_FREE:
297 		trace1(TR_xdr_short, 1);
298 		return (TRUE);
299 	}
300 	trace1(TR_xdr_short, 1);
301 	return (FALSE);
302 }
303 
304 /*
305  * XDR unsigned short integers
306  */
307 bool_t
308 xdr_u_short(XDR *xdrs, ushort_t *usp)
309 {
310 	uint_t i;
311 	bool_t dummy;
312 
313 
314 	trace1(TR_xdr_u_short, 0);
315 	switch (xdrs->x_op) {
316 
317 	case XDR_ENCODE:
318 		i = (uint_t)*usp;
319 		dummy = XDR_PUTINT32(xdrs, (int *)&i);
320 		trace1(TR_xdr_u_short, 1);
321 		return (dummy);
322 
323 	case XDR_DECODE:
324 		if (!XDR_GETINT32(xdrs, (int *)&i)) {
325 #ifdef KERNEL
326 			printf("xdr_u_short: decode FAILED\n");
327 #endif
328 			trace1(TR_xdr_u_short, 1);
329 			return (FALSE);
330 		}
331 		*usp = (ushort_t)i;
332 		trace1(TR_xdr_u_short, 1);
333 		return (TRUE);
334 
335 	case XDR_FREE:
336 		trace1(TR_xdr_u_short, 1);
337 		return (TRUE);
338 	}
339 #ifdef KERNEL
340 	printf("xdr_u_short: bad op FAILED\n");
341 #endif
342 	trace1(TR_xdr_u_short, 1);
343 	return (FALSE);
344 }
345 
346 
347 /*
348  * XDR a char
349  */
350 bool_t
351 xdr_char(XDR *xdrs, char *cp)
352 {
353 	int i;
354 
355 	trace1(TR_xdr_char, 0);
356 
357 	if (xdrs->x_op == XDR_ENCODE)
358 		i = (*cp);
359 
360 	if (! xdr_int(xdrs, &i)) {
361 		trace1(TR_xdr_char, 1);
362 		return (FALSE);
363 	}
364 	if (xdrs->x_op == XDR_DECODE)
365 		*cp = (char)i;
366 	trace1(TR_xdr_char, 1);
367 	return (TRUE);
368 }
369 
370 #ifndef KERNEL
371 /*
372  * XDR an unsigned char
373  */
374 bool_t
375 xdr_u_char(XDR *xdrs, uchar_t *cp)
376 {
377 	int i;
378 
379 	trace1(TR_xdr_u_char, 0);
380 	if (xdrs->x_op == XDR_ENCODE)
381 		i = (*cp);
382 	if (! xdr_int(xdrs, &i)) {
383 		trace1(TR_xdr_u_char, 1);
384 		return (FALSE);
385 	}
386 	if (xdrs->x_op == XDR_DECODE)
387 		*cp = (uchar_t)i;
388 	trace1(TR_xdr_u_char, 1);
389 	return (TRUE);
390 }
391 #endif /* !KERNEL */
392 
393 /*
394  * XDR booleans
395  */
396 bool_t
397 xdr_bool(XDR *xdrs, bool_t *bp)
398 {
399 	int i;
400 	bool_t dummy;
401 
402 	trace1(TR_xdr_bool, 0);
403 	switch (xdrs->x_op) {
404 
405 	case XDR_ENCODE:
406 		i = *bp ? XDR_TRUE : XDR_FALSE;
407 		dummy = XDR_PUTINT32(xdrs, &i);
408 		trace1(TR_xdr_bool, 1);
409 		return (dummy);
410 
411 	case XDR_DECODE:
412 		if (!XDR_GETINT32(xdrs, &i)) {
413 #ifdef KERNEL
414 			printf("xdr_bool: decode FAILED\n");
415 #endif
416 			trace1(TR_xdr_bool, 1);
417 			return (FALSE);
418 		}
419 		*bp = (i == XDR_FALSE) ? FALSE : TRUE;
420 		trace1(TR_xdr_bool, 1);
421 		return (TRUE);
422 
423 	case XDR_FREE:
424 		trace1(TR_xdr_bool, 1);
425 		return (TRUE);
426 	}
427 #ifdef KERNEL
428 	printf("xdr_bool: bad op FAILED\n");
429 #endif
430 	trace1(TR_xdr_bool, 1);
431 	return (FALSE);
432 }
433 
434 /*
435  * XDR enumerations
436  */
437 bool_t
438 xdr_enum(XDR *xdrs, enum_t *ep)
439 {
440 	bool_t dummy;
441 
442 #ifndef lint
443 	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */
444 
445 	/*
446 	 * enums are treated as ints
447 	 */
448 	trace1(TR_xdr_enum, 0);
449 	if (sizeof (enum sizecheck) == sizeof (int32_t)) {
450 		dummy = xdr_int(xdrs, (int *)ep);
451 		trace1(TR_xdr_enum, 1);
452 		return (dummy);
453 	} else if (sizeof (enum sizecheck) == sizeof (short)) {
454 		dummy = xdr_short(xdrs, (short *)ep);
455 		trace1(TR_xdr_enum, 1);
456 		return (dummy);
457 	} else if (sizeof (enum sizecheck) == sizeof (char)) {
458 		dummy = xdr_char(xdrs, (char *)ep);
459 		trace1(TR_xdr_enum, 1);
460 		return (dummy);
461 	} else {
462 		trace1(TR_xdr_enum, 1);
463 		return (FALSE);
464 	}
465 #else
466 	trace1(TR_xdr_enum, 0);
467 	(void) (xdr_char(xdrs, (char *)ep));
468 	(void) (xdr_short(xdrs, (short *)ep));
469 	dummy = xdr_int(xdrs, (int32_t *)ep);
470 	trace1(TR_xdr_enum, 1);
471 	return (dummy);
472 #endif
473 }
474 
475 /*
476  * XDR opaque data
477  * Allows the specification of a fixed size sequence of opaque bytes.
478  * cp points to the opaque object and cnt gives the byte length.
479  */
480 bool_t
481 xdr_opaque(XDR *xdrs, caddr_t cp, uint_t cnt)
482 {
483 	bool_t dummy;
484 	register uint_t rndup;
485 	char crud[BYTES_PER_XDR_UNIT];
486 
487 	/*
488 	 * if no data we are done
489 	 */
490 	trace2(TR_xdr_opaque, 0, cnt);
491 	if (cnt == 0) {
492 		trace1(TR_xdr_opaque, 1);
493 		return (TRUE);
494 	}
495 
496 	/*
497 	 * round byte count to full xdr units
498 	 */
499 	rndup = cnt % BYTES_PER_XDR_UNIT;
500 	if ((int)rndup > 0)
501 		rndup = BYTES_PER_XDR_UNIT - rndup;
502 
503 	if (xdrs->x_op == XDR_DECODE) {
504 		if (!XDR_GETBYTES(xdrs, cp, cnt)) {
505 #ifdef KERNEL
506 			printf("xdr_opaque: decode FAILED\n");
507 #endif
508 			trace1(TR_xdr_opaque, 1);
509 			return (FALSE);
510 		}
511 		if (rndup == 0) {
512 			trace1(TR_xdr_opaque, 1);
513 			return (TRUE);
514 		}
515 		dummy = XDR_GETBYTES(xdrs, crud, rndup);
516 		trace1(TR_xdr_opaque, 1);
517 		return (dummy);
518 	}
519 
520 	if (xdrs->x_op == XDR_ENCODE) {
521 
522 		if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
523 #ifdef KERNEL
524 			printf("xdr_opaque: encode FAILED\n");
525 #endif
526 			trace1(TR_xdr_opaque, 1);
527 			return (FALSE);
528 		}
529 		if (rndup == 0) {
530 			trace1(TR_xdr_opaque, 1);
531 			return (TRUE);
532 		}
533 		dummy = XDR_PUTBYTES(xdrs, (caddr_t)&xdr_zero[0], rndup);
534 		trace1(TR_xdr_opaque, 1);
535 		return (dummy);
536 	}
537 
538 	if (xdrs->x_op == XDR_FREE) {
539 		trace1(TR_xdr_opaque, 1);
540 		return (TRUE);
541 	}
542 
543 #ifdef KERNEL
544 	printf("xdr_opaque: bad op FAILED\n");
545 #endif
546 	trace1(TR_xdr_opaque, 1);
547 	return (FALSE);
548 }
549 
550 /*
551  * XDR counted bytes
552  * *cpp is a pointer to the bytes, *sizep is the count.
553  * If *cpp is NULL maxsize bytes are allocated
554  */
555 
556 #ifndef KERNEL
557 static const char xdr_err[] = "xdr_%s: out of memory";
558 #endif
559 
560 bool_t
561 xdr_bytes(XDR *xdrs, char **cpp, uint_t *sizep, uint_t maxsize)
562 {
563 	bool_t dummy;
564 	register char *sp = *cpp;  /* sp is the actual string pointer */
565 	register uint_t nodesize;
566 
567 	/*
568 	 * first deal with the length since xdr bytes are counted
569 	 * We decided not to use MACRO XDR_U_INT here, because the
570 	 * advantages here will be miniscule compared to xdr_bytes.
571 	 * This saved us 100 bytes in the library size.
572 	 */
573 	trace2(TR_xdr_bytes, 0, maxsize);
574 	if (! xdr_u_int(xdrs, sizep)) {
575 #ifdef KERNEL
576 		printf("xdr_bytes: size FAILED\n");
577 #endif
578 		trace1(TR_xdr_bytes, 1);
579 		return (FALSE);
580 	}
581 	nodesize = *sizep;
582 	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
583 #ifdef KERNEL
584 		printf("xdr_bytes: bad size FAILED\n");
585 #endif
586 		trace1(TR_xdr_bytes, 1);
587 		return (FALSE);
588 	}
589 
590 	/*
591 	 * now deal with the actual bytes
592 	 */
593 	switch (xdrs->x_op) {
594 
595 	case XDR_DECODE:
596 		if (nodesize == 0) {
597 			trace1(TR_xdr_bytes, 1);
598 			return (TRUE);
599 		}
600 		if (sp == NULL) {
601 			*cpp = sp = (char *)mem_alloc(nodesize);
602 		}
603 #ifndef KERNEL
604 		if (sp == NULL) {
605 			(void) syslog(LOG_ERR, xdr_err, (const char *)"bytes");
606 			trace1(TR_xdr_bytes, 1);
607 			return (FALSE);
608 		}
609 #endif
610 		/*FALLTHROUGH*/
611 
612 	case XDR_ENCODE:
613 		dummy = xdr_opaque(xdrs, sp, nodesize);
614 		trace1(TR_xdr_bytes, 1);
615 		return (dummy);
616 
617 	case XDR_FREE:
618 		if (sp != NULL) {
619 			mem_free(sp, nodesize);
620 			*cpp = NULL;
621 		}
622 		trace1(TR_xdr_bytes, 1);
623 		return (TRUE);
624 	}
625 #ifdef KERNEL
626 	printf("xdr_bytes: bad op FAILED\n");
627 #endif
628 	trace1(TR_xdr_bytes, 1);
629 	return (FALSE);
630 }
631 
632 /*
633  * Implemented here due to commonality of the object.
634  */
635 bool_t
636 xdr_netobj(XDR *xdrs, struct netobj *np)
637 {
638 	bool_t dummy;
639 
640 	trace1(TR_xdr_netobj, 0);
641 	dummy = xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ);
642 	trace1(TR_xdr_netobj, 1);
643 	return (dummy);
644 }
645 
646 /*
647  * XDR a descriminated union
648  * Support routine for discriminated unions.
649  * You create an array of xdrdiscrim structures, terminated with
650  * an entry with a null procedure pointer.  The routine gets
651  * the discriminant value and then searches the array of xdrdiscrims
652  * looking for that value.  It calls the procedure given in the xdrdiscrim
653  * to handle the discriminant.  If there is no specific routine a default
654  * routine may be called.
655  * If there is no specific or default routine an error is returned.
656  */
657 bool_t
658 xdr_union(XDR *xdrs, enum_t *dscmp, char *unp,
659 		const struct xdr_discrim *choices, xdrproc_t dfault)
660 {
661 	register enum_t dscm;
662 	bool_t dummy;
663 
664 	/*
665 	 * we deal with the discriminator;  it's an enum
666 	 */
667 	trace1(TR_xdr_union, 0);
668 	if (! xdr_enum(xdrs, dscmp)) {
669 #ifdef KERNEL
670 		printf("xdr_enum: dscmp FAILED\n");
671 #endif
672 		trace1(TR_xdr_union, 1);
673 		return (FALSE);
674 	}
675 	dscm = *dscmp;
676 
677 	/*
678 	 * search choices for a value that matches the discriminator.
679 	 * if we find one, execute the xdr routine for that value.
680 	 */
681 	for (; choices->proc != NULL_xdrproc_t; choices++) {
682 		if (choices->value == dscm) {
683 			dummy = (*(choices->proc))(xdrs, unp, LASTUNSIGNED);
684 			trace1(TR_xdr_union, 1);
685 			return (dummy);
686 		}
687 	}
688 
689 	/*
690 	 * no match - execute the default xdr routine if there is one
691 	 */
692 	dummy = (dfault == NULL_xdrproc_t) ? FALSE :
693 	    (*dfault)(xdrs, unp, LASTUNSIGNED);
694 	trace1(TR_xdr_union, 1);
695 	return (dummy);
696 }
697 
698 
699 /*
700  * Non-portable xdr primitives.
701  * Care should be taken when moving these routines to new architectures.
702  */
703 
704 
705 /*
706  * XDR null terminated ASCII strings
707  * xdr_string deals with "C strings" - arrays of bytes that are
708  * terminated by a NULL character.  The parameter cpp references a
709  * pointer to storage; If the pointer is null, then the necessary
710  * storage is allocated.  The last parameter is the max allowed length
711  * of the string as specified by a protocol.
712  */
713 bool_t
714 xdr_string(XDR *xdrs, char **cpp, uint_t maxsize)
715 {
716 	bool_t dummy;
717 	register char *newsp, *sp = *cpp;  /* sp is the actual string pointer */
718 	uint_t size, block;
719 	uint64_t bytesread;
720 
721 	/*
722 	 * first deal with the length since xdr strings are counted-strings
723 	 */
724 	trace2(TR_xdr_string, 0, maxsize);
725 	switch (xdrs->x_op) {
726 	case XDR_FREE:
727 		if (sp == NULL) {
728 			trace1(TR_xdr_string, 1);
729 			return (TRUE);	/* already free */
730 		}
731 		/*FALLTHROUGH*/
732 	case XDR_ENCODE:
733 		size = (sp != NULL) ? (uint_t)strlen(sp) : 0;
734 		break;
735 	}
736 	/*
737 	 * We decided not to use MACRO XDR_U_INT here, because the
738 	 * advantages here will be miniscule compared to xdr_string.
739 	 * This saved us 100 bytes in the library size.
740 	 */
741 	if (! xdr_u_int(xdrs, &size)) {
742 		trace1(TR_xdr_string, 1);
743 		return (FALSE);
744 	}
745 	if (size > maxsize) {
746 		trace1(TR_xdr_string, 1);
747 		return (FALSE);
748 	}
749 
750 	/*
751 	 * now deal with the actual bytes
752 	 */
753 	switch (xdrs->x_op) {
754 
755 	case XDR_DECODE:
756 		/* if buffer is already given, call xdr_opaque() directly */
757 		if (sp != NULL) {
758 			dummy = xdr_opaque(xdrs, sp, size);
759 			sp[size] = 0;
760 			trace1(TR_xdr_string, 1);
761 			return (dummy);
762 		}
763 
764 		/*
765 		 * We have to allocate a buffer of size 'size'. To avoid
766 		 * malloc()ing one huge chunk, we'll read the bytes in max
767 		 * FRAGMENT size blocks and keep realloc()ing. 'block' is
768 		 * the number of bytes to read in each xdr_opaque() and
769 		 * 'bytesread' is what we have already read. sp is NULL
770 		 * when we are in the loop for the first time.
771 		 */
772 		bytesread = 0;
773 		do {
774 			block = MIN(size - bytesread, FRAGMENT);
775 			/*
776 			 * allocate enough for 'bytesread + block' bytes and
777 			 * one extra for the terminating NULL.
778 			 */
779 			newsp = realloc(sp, bytesread + block + 1);
780 			if (newsp == NULL) {
781 				if (sp != NULL)
782 					free(sp);
783 				trace1(TR_xdr_string, 1);
784 				return (FALSE);
785 			}
786 			sp = newsp;
787 			if (!xdr_opaque(xdrs, &sp[bytesread], block)) {
788 				free(sp);
789 				trace1(TR_xdr_string, 1);
790 				return (FALSE);
791 			}
792 			bytesread += block;
793 		} while (bytesread < size);
794 
795 		sp[bytesread] = 0; /* terminate the string with a NULL */
796 		*cpp = sp;
797 		trace1(TR_xdr_string, 1);
798 		return (TRUE);
799 	case XDR_ENCODE:
800 		dummy = xdr_opaque(xdrs, sp, size);
801 		trace1(TR_xdr_string, 1);
802 		return (dummy);
803 	case XDR_FREE:
804 		free(sp);
805 		*cpp = NULL;
806 		trace1(TR_xdr_string, 1);
807 		return (TRUE);
808 	}
809 #ifdef KERNEL
810 	printf("xdr_string: bad op FAILED\n");
811 #endif
812 	trace1(TR_xdr_string, 1);
813 	return (FALSE);
814 }
815 
816 bool_t
817 xdr_hyper(XDR *xdrs, longlong_t *hp)
818 {
819 	bool_t	dummy;
820 
821 	trace1(TR_xdr_hyper, 0);
822 	if (xdrs->x_op == XDR_ENCODE) {
823 #if defined(_LONG_LONG_HTOL)
824 		if (XDR_PUTINT32(xdrs, (int *)hp) == TRUE) {
825 			dummy = XDR_PUTINT32(xdrs, (int *)((char *)hp +
826 				BYTES_PER_XDR_UNIT));
827 			trace1(TR_xdr_hyper, 1);
828 			return (dummy);
829 		}
830 
831 #else
832 		if (XDR_PUTINT32(xdrs, (int *)((char *)hp +
833 			BYTES_PER_XDR_UNIT)) == TRUE) {
834 			dummy = XDR_PUTINT32(xdrs, (int32_t *)hp);
835 			trace1(TR_xdr_hyper, 1);
836 			return (dummy);
837 		}
838 
839 #endif
840 		trace1(TR_xdr_hyper, 1);
841 		return (FALSE);
842 
843 	} else if (xdrs->x_op == XDR_DECODE) {
844 #if defined(_LONG_LONG_HTOL)
845 		if (XDR_GETINT32(xdrs, (int *)hp) == FALSE ||
846 		    (XDR_GETINT32(xdrs, (int *)((char *)hp +
847 				BYTES_PER_XDR_UNIT)) == FALSE)) {
848 			trace1(TR_xdr_hyper, 1);
849 			return (FALSE);
850 		}
851 #else
852 		if ((XDR_GETINT32(xdrs, (int *)((char *)hp +
853 				BYTES_PER_XDR_UNIT)) == FALSE) ||
854 				(XDR_GETINT32(xdrs, (int *)hp) == FALSE)) {
855 			trace1(TR_xdr_hyper, 1);
856 			return (FALSE);
857 		}
858 #endif
859 		trace1(TR_xdr_hyper, 1);
860 		return (TRUE);
861 	}
862 	trace1(TR_xdr_hyper, 1);
863 	return (TRUE);
864 }
865 
866 bool_t
867 xdr_u_hyper(XDR *xdrs, u_longlong_t *hp)
868 {
869 	bool_t dummy;
870 
871 	trace1(TR_xdr_u_hyper, 0);
872 	dummy = xdr_hyper(xdrs, (longlong_t *)hp);
873 	trace1(TR_xdr_u_hyper, 1);
874 	return (dummy);
875 }
876 
877 bool_t
878 xdr_longlong_t(XDR *xdrs, longlong_t *hp)
879 {
880 	bool_t dummy;
881 
882 	trace1(TR_xdr_longlong_t, 0);
883 	dummy = xdr_hyper(xdrs, hp);
884 	trace1(TR_xdr_longlong_t, 1);
885 	return (dummy);
886 }
887 
888 bool_t
889 xdr_u_longlong_t(XDR *xdrs, u_longlong_t *hp)
890 {
891 	bool_t dummy;
892 
893 	trace1(TR_xdr_u_longlong_t, 0);
894 	dummy = xdr_hyper(xdrs, (longlong_t *)hp);
895 	trace1(TR_xdr_u_longlong_t, 1);
896 	return (dummy);
897 }
898 /*
899  * The following routine is part of a workaround for bug
900  * #1128007.  When it is fixed, this routine should be
901  * removed.
902  */
903 bool_t
904 xdr_ulonglong_t(XDR *xdrs, u_longlong_t *hp)
905 {
906 	bool_t dummy;
907 
908 	trace1(TR_xdr_u_longlong_t, 0);
909 	dummy = xdr_hyper(xdrs, (longlong_t *)hp);
910 	trace1(TR_xdr_u_longlong_t, 1);
911 	return (dummy);
912 }
913 
914 #ifndef KERNEL
915 /*
916  * Wrapper for xdr_string that can be called directly from
917  * routines like clnt_call
918  */
919 bool_t
920 xdr_wrapstring(XDR *xdrs, char **cpp)
921 {
922 	trace1(TR_xdr_wrapstring, 0);
923 	if (xdr_string(xdrs, cpp, LASTUNSIGNED)) {
924 		trace1(TR_xdr_wrapstring, 1);
925 		return (TRUE);
926 	}
927 	trace1(TR_xdr_wrapstring, 1);
928 	return (FALSE);
929 }
930 #endif /* !KERNEL */
931