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 2008 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 booleans 311 * 312 * PSARC 2003/523 Contract Private Interface 313 * xdr_bool 314 * Changes must be reviewed by Solaris File Sharing 315 * Changes must be communicated to contract-2003-523@sun.com 316 */ 317 bool_t 318 xdr_bool(XDR *xdrs, bool_t *bp) 319 { 320 int32_t i32b; 321 322 switch (xdrs->x_op) { 323 324 case XDR_ENCODE: 325 i32b = *bp ? XDR_TRUE : XDR_FALSE; 326 return (XDR_PUTINT32(xdrs, &i32b)); 327 328 case XDR_DECODE: 329 if (!XDR_GETINT32(xdrs, &i32b)) { 330 return (FALSE); 331 } 332 *bp = (i32b == XDR_FALSE) ? FALSE : TRUE; 333 return (TRUE); 334 335 case XDR_FREE: 336 return (TRUE); 337 } 338 return (FALSE); 339 } 340 341 /* 342 * XDR enumerations 343 * 344 * PSARC 2003/523 Contract Private Interface 345 * xdr_enum 346 * Changes must be reviewed by Solaris File Sharing 347 * Changes must be communicated to contract-2003-523@sun.com 348 */ 349 #ifndef lint 350 enum sizecheck { SIZEVAL } sizecheckvar; /* used to find the size of */ 351 /* an enum */ 352 #endif 353 bool_t 354 xdr_enum(XDR *xdrs, enum_t *ep) 355 { 356 #ifndef lint 357 /* 358 * enums are treated as ints 359 */ 360 if (sizeof (sizecheckvar) == sizeof (int32_t)) { 361 return (xdr_int(xdrs, (int32_t *)ep)); 362 } else if (sizeof (sizecheckvar) == sizeof (short)) { 363 return (xdr_short(xdrs, (short *)ep)); 364 } else { 365 return (FALSE); 366 } 367 #else 368 (void) (xdr_short(xdrs, (short *)ep)); 369 return (xdr_int(xdrs, (int32_t *)ep)); 370 #endif 371 } 372 373 /* 374 * XDR opaque data 375 * Allows the specification of a fixed size sequence of opaque bytes. 376 * cp points to the opaque object and cnt gives the byte length. 377 * 378 * PSARC 2003/523 Contract Private Interface 379 * xdr_opaque 380 * Changes must be reviewed by Solaris File Sharing 381 * Changes must be communicated to contract-2003-523@sun.com 382 */ 383 bool_t 384 xdr_opaque(XDR *xdrs, caddr_t cp, const uint_t cnt) 385 { 386 uint_t rndup; 387 static char crud[BYTES_PER_XDR_UNIT]; 388 389 /* 390 * if no data we are done 391 */ 392 if (cnt == 0) 393 return (TRUE); 394 395 /* 396 * round byte count to full xdr units 397 */ 398 rndup = cnt % BYTES_PER_XDR_UNIT; 399 if (rndup != 0) 400 rndup = BYTES_PER_XDR_UNIT - rndup; 401 402 if (xdrs->x_op == XDR_DECODE) { 403 if (!XDR_GETBYTES(xdrs, cp, cnt)) { 404 return (FALSE); 405 } 406 if (rndup == 0) 407 return (TRUE); 408 return (XDR_GETBYTES(xdrs, (caddr_t)crud, rndup)); 409 } 410 411 if (xdrs->x_op == XDR_ENCODE) { 412 if (!XDR_PUTBYTES(xdrs, cp, cnt)) { 413 return (FALSE); 414 } 415 if (rndup == 0) 416 return (TRUE); 417 return (XDR_PUTBYTES(xdrs, xdr_zero, rndup)); 418 } 419 420 if (xdrs->x_op == XDR_FREE) 421 return (TRUE); 422 423 return (FALSE); 424 } 425 426 /* 427 * XDR counted bytes 428 * *cpp is a pointer to the bytes, *sizep is the count. 429 * If *cpp is NULL maxsize bytes are allocated 430 * 431 * PSARC 2003/523 Contract Private Interface 432 * xdr_bytes 433 * Changes must be reviewed by Solaris File Sharing 434 * Changes must be communicated to contract-2003-523@sun.com 435 */ 436 bool_t 437 xdr_bytes(XDR *xdrs, char **cpp, uint_t *sizep, const uint_t maxsize) 438 { 439 char *sp = *cpp; /* sp is the actual string pointer */ 440 uint_t nodesize; 441 442 /* 443 * first deal with the length since xdr bytes are counted 444 */ 445 if (!xdr_u_int(xdrs, sizep)) { 446 return (FALSE); 447 } 448 nodesize = *sizep; 449 if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) { 450 return (FALSE); 451 } 452 453 /* 454 * now deal with the actual bytes 455 */ 456 switch (xdrs->x_op) { 457 case XDR_DECODE: 458 if (nodesize == 0) 459 return (TRUE); 460 if (sp == NULL) 461 *cpp = sp = (char *)mem_alloc(nodesize); 462 /* FALLTHROUGH */ 463 464 case XDR_ENCODE: 465 return (xdr_opaque(xdrs, sp, nodesize)); 466 467 case XDR_FREE: 468 if (sp != NULL) { 469 mem_free(sp, nodesize); 470 *cpp = NULL; 471 } 472 return (TRUE); 473 } 474 return (FALSE); 475 } 476 477 /* 478 * Implemented here due to commonality of the object. 479 */ 480 bool_t 481 xdr_netobj(XDR *xdrs, struct netobj *np) 482 { 483 return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ)); 484 } 485 486 /* 487 * XDR a descriminated union 488 * Support routine for discriminated unions. 489 * You create an array of xdrdiscrim structures, terminated with 490 * an entry with a null procedure pointer. The routine gets 491 * the discriminant value and then searches the array of xdrdiscrims 492 * looking for that value. It calls the procedure given in the xdrdiscrim 493 * to handle the discriminant. If there is no specific routine a default 494 * routine may be called. 495 * If there is no specific or default routine an error is returned. 496 */ 497 bool_t 498 xdr_union(XDR *xdrs, enum_t *dscmp, char *unp, 499 const struct xdr_discrim *choices, const xdrproc_t dfault) 500 { 501 enum_t dscm; 502 503 /* 504 * we deal with the discriminator; it's an enum 505 */ 506 if (!xdr_enum(xdrs, dscmp)) { 507 return (FALSE); 508 } 509 dscm = *dscmp; 510 511 /* 512 * search choices for a value that matches the discriminator. 513 * if we find one, execute the xdr routine for that value. 514 */ 515 for (; choices->proc != NULL_xdrproc_t; choices++) { 516 if (choices->value == dscm) 517 return ((*(choices->proc))(xdrs, unp, LASTUNSIGNED)); 518 } 519 520 /* 521 * no match - execute the default xdr routine if there is one 522 */ 523 return ((dfault == NULL_xdrproc_t) ? FALSE : 524 (*dfault)(xdrs, unp, LASTUNSIGNED)); 525 } 526 527 528 /* 529 * Non-portable xdr primitives. 530 * Care should be taken when moving these routines to new architectures. 531 */ 532 533 534 /* 535 * XDR null terminated ASCII strings 536 * xdr_string deals with "C strings" - arrays of bytes that are 537 * terminated by a NULL character. The parameter cpp references a 538 * pointer to storage; If the pointer is null, then the necessary 539 * storage is allocated. The last parameter is the max allowed length 540 * of the string as specified by a protocol. 541 */ 542 bool_t 543 xdr_string(XDR *xdrs, char **cpp, const uint_t maxsize) 544 { 545 char *sp = *cpp; /* sp is the actual string pointer */ 546 uint_t size; 547 uint_t nodesize; 548 549 /* 550 * first deal with the length since xdr strings are counted-strings 551 */ 552 switch (xdrs->x_op) { 553 case XDR_FREE: 554 if (sp == NULL) 555 return (TRUE); /* already free */ 556 /* FALLTHROUGH */ 557 case XDR_ENCODE: 558 size = (sp != NULL) ? (uint_t)strlen(sp) : 0; 559 break; 560 case XDR_DECODE: 561 break; 562 } 563 if (!xdr_u_int(xdrs, &size)) { 564 return (FALSE); 565 } 566 if (size > maxsize) { 567 return (FALSE); 568 } 569 nodesize = size + 1; 570 571 /* 572 * now deal with the actual bytes 573 */ 574 switch (xdrs->x_op) { 575 case XDR_DECODE: 576 if (nodesize == 0) 577 return (TRUE); 578 if (sp == NULL) 579 sp = (char *)mem_alloc(nodesize); 580 sp[size] = 0; 581 if (!xdr_opaque(xdrs, sp, size)) { 582 /* 583 * free up memory if allocated here 584 */ 585 if (*cpp == NULL) { 586 mem_free(sp, nodesize); 587 } 588 return (FALSE); 589 } 590 if (strlen(sp) != size) { 591 if (*cpp == NULL) { 592 mem_free(sp, nodesize); 593 } 594 return (FALSE); 595 } 596 *cpp = sp; 597 return (TRUE); 598 599 case XDR_ENCODE: 600 return (xdr_opaque(xdrs, sp, size)); 601 602 case XDR_FREE: 603 mem_free(sp, nodesize); 604 *cpp = NULL; 605 return (TRUE); 606 } 607 return (FALSE); 608 } 609 610 /* 611 * Wrapper for xdr_string that can be called directly from 612 * routines like clnt_call 613 */ 614 bool_t 615 xdr_wrapstring(XDR *xdrs, char **cpp) 616 { 617 if (xdr_string(xdrs, cpp, LASTUNSIGNED)) 618 return (TRUE); 619 return (FALSE); 620 } 621