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@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@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@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@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@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@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