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