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 (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
     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
     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 (at) sun.com
    102  */
    103 bool_t
    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 (at) sun.com
    125  */
    126 bool_t
    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
    149 xdr_long(XDR *xdrs, long *ip)
    150 {
    151 	return (xdr_int(xdrs, (int *)ip));
    152 }
    153 
    154 bool_t
    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
    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
    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
    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
    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
    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
    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 (at) sun.com
    339  */
    340 bool_t
    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 (at) 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
    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 (at) sun.com
    405  */
    406 bool_t
    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 (at) sun.com
    458  */
    459 bool_t
    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
    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
    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
    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
    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
    664 xdr_wrapstring(XDR *xdrs, char **cpp)
    665 {
    666 	if (xdr_string(xdrs, cpp, LASTUNSIGNED))
    667 		return (TRUE);
    668 	return (FALSE);
    669 }
    670