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 "%Z%%M% %I% %E% 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@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@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@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@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@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@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