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