1/*	$NetBSD: xdr.c,v 1.22 2000/07/06 03:10:35 christos Exp $	*/
2
3/*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part.  Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California  94043
30 */
31
32#if defined(LIBC_SCCS) && !defined(lint)
33static char *sccsid2 = "@(#)xdr.c 1.35 87/08/12";
34static char *sccsid = "@(#)xdr.c	2.1 88/07/29 4.0 RPCSRC";
35#endif
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD$");
38
39/*
40 * xdr.c, Generic XDR routines implementation.
41 *
42 * Copyright (C) 1986, Sun Microsystems, Inc.
43 *
44 * These are the "generic" xdr routines used to serialize and de-serialize
45 * most common data items.  See xdr.h for more info on the interface to
46 * xdr.
47 */
48
49#include <sys/param.h>
50#include <sys/systm.h>
51#include <sys/kernel.h>
52#include <sys/malloc.h>
53#include <sys/module.h>
54
55#include <rpc/rpc.h>
56#include <rpc/rpc_com.h>
57#include <rpc/types.h>
58#include <rpc/xdr.h>
59
60typedef quad_t          longlong_t;     /* ANSI long long type */
61typedef u_quad_t        u_longlong_t;   /* ANSI unsigned long long type */
62
63/*
64 * constants specific to the xdr "protocol"
65 */
66#define XDR_FALSE	((long) 0)
67#define XDR_TRUE	((long) 1)
68
69MALLOC_DEFINE(M_RPC, "rpc", "Remote Procedure Call");
70
71/*
72 * for unit alignment
73 */
74static const 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 */
80void
81xdr_free(xdrproc_t proc, void *objp)
82{
83	XDR x;
84
85	x.x_op = XDR_FREE;
86	(*proc)(&x, objp);
87}
88
89/*
90 * XDR nothing
91 */
92bool_t
93xdr_void(void)
94{
95
96	return (TRUE);
97}
98
99
100/*
101 * XDR integers
102 */
103bool_t
104xdr_int(XDR *xdrs, int *ip)
105{
106	long l;
107
108	switch (xdrs->x_op) {
109
110	case XDR_ENCODE:
111		l = (long) *ip;
112		return (XDR_PUTLONG(xdrs, &l));
113
114	case XDR_DECODE:
115		if (!XDR_GETLONG(xdrs, &l)) {
116			return (FALSE);
117		}
118		*ip = (int) l;
119		return (TRUE);
120
121	case XDR_FREE:
122		return (TRUE);
123	}
124	/* NOTREACHED */
125	return (FALSE);
126}
127
128/*
129 * XDR unsigned integers
130 */
131bool_t
132xdr_u_int(XDR *xdrs, u_int *up)
133{
134	u_long l;
135
136	switch (xdrs->x_op) {
137
138	case XDR_ENCODE:
139		l = (u_long) *up;
140		return (XDR_PUTLONG(xdrs, (long *)&l));
141
142	case XDR_DECODE:
143		if (!XDR_GETLONG(xdrs, (long *)&l)) {
144			return (FALSE);
145		}
146		*up = (u_int) l;
147		return (TRUE);
148
149	case XDR_FREE:
150		return (TRUE);
151	}
152	/* NOTREACHED */
153	return (FALSE);
154}
155
156
157/*
158 * XDR long integers
159 * same as xdr_u_long - open coded to save a proc call!
160 */
161bool_t
162xdr_long(XDR *xdrs, long *lp)
163{
164	switch (xdrs->x_op) {
165	case XDR_ENCODE:
166		return (XDR_PUTLONG(xdrs, lp));
167	case XDR_DECODE:
168		return (XDR_GETLONG(xdrs, lp));
169	case XDR_FREE:
170		return (TRUE);
171	}
172	/* NOTREACHED */
173	return (FALSE);
174}
175
176/*
177 * XDR unsigned long integers
178 * same as xdr_long - open coded to save a proc call!
179 */
180bool_t
181xdr_u_long(XDR *xdrs, u_long *ulp)
182{
183	switch (xdrs->x_op) {
184	case XDR_ENCODE:
185		return (XDR_PUTLONG(xdrs, (long *)ulp));
186	case XDR_DECODE:
187		return (XDR_GETLONG(xdrs, (long *)ulp));
188	case XDR_FREE:
189		return (TRUE);
190	}
191	/* NOTREACHED */
192	return (FALSE);
193}
194
195
196/*
197 * XDR 32-bit integers
198 * same as xdr_uint32_t - open coded to save a proc call!
199 */
200bool_t
201xdr_int32_t(XDR *xdrs, int32_t *int32_p)
202{
203	long l;
204
205	switch (xdrs->x_op) {
206
207	case XDR_ENCODE:
208		l = (long) *int32_p;
209		return (XDR_PUTLONG(xdrs, &l));
210
211	case XDR_DECODE:
212		if (!XDR_GETLONG(xdrs, &l)) {
213			return (FALSE);
214		}
215		*int32_p = (int32_t) l;
216		return (TRUE);
217
218	case XDR_FREE:
219		return (TRUE);
220	}
221	/* NOTREACHED */
222	return (FALSE);
223}
224
225/*
226 * XDR unsigned 32-bit integers
227 * same as xdr_int32_t - open coded to save a proc call!
228 */
229bool_t
230xdr_uint32_t(XDR *xdrs, uint32_t *uint32_p)
231{
232	u_long l;
233
234	switch (xdrs->x_op) {
235
236	case XDR_ENCODE:
237		l = (u_long) *uint32_p;
238		return (XDR_PUTLONG(xdrs, (long *)&l));
239
240	case XDR_DECODE:
241		if (!XDR_GETLONG(xdrs, (long *)&l)) {
242			return (FALSE);
243		}
244		*uint32_p = (uint32_t) l;
245		return (TRUE);
246
247	case XDR_FREE:
248		return (TRUE);
249	}
250	/* NOTREACHED */
251	return (FALSE);
252}
253
254
255/*
256 * XDR short integers
257 */
258bool_t
259xdr_short(XDR *xdrs, short *sp)
260{
261	long l;
262
263	switch (xdrs->x_op) {
264
265	case XDR_ENCODE:
266		l = (long) *sp;
267		return (XDR_PUTLONG(xdrs, &l));
268
269	case XDR_DECODE:
270		if (!XDR_GETLONG(xdrs, &l)) {
271			return (FALSE);
272		}
273		*sp = (short) l;
274		return (TRUE);
275
276	case XDR_FREE:
277		return (TRUE);
278	}
279	/* NOTREACHED */
280	return (FALSE);
281}
282
283/*
284 * XDR unsigned short integers
285 */
286bool_t
287xdr_u_short(XDR *xdrs, u_short *usp)
288{
289	u_long l;
290
291	switch (xdrs->x_op) {
292
293	case XDR_ENCODE:
294		l = (u_long) *usp;
295		return (XDR_PUTLONG(xdrs, (long *)&l));
296
297	case XDR_DECODE:
298		if (!XDR_GETLONG(xdrs, (long *)&l)) {
299			return (FALSE);
300		}
301		*usp = (u_short) l;
302		return (TRUE);
303
304	case XDR_FREE:
305		return (TRUE);
306	}
307	/* NOTREACHED */
308	return (FALSE);
309}
310
311
312/*
313 * XDR 16-bit integers
314 */
315bool_t
316xdr_int16_t(XDR *xdrs, int16_t *int16_p)
317{
318	long l;
319
320	switch (xdrs->x_op) {
321
322	case XDR_ENCODE:
323		l = (long) *int16_p;
324		return (XDR_PUTLONG(xdrs, &l));
325
326	case XDR_DECODE:
327		if (!XDR_GETLONG(xdrs, &l)) {
328			return (FALSE);
329		}
330		*int16_p = (int16_t) l;
331		return (TRUE);
332
333	case XDR_FREE:
334		return (TRUE);
335	}
336	/* NOTREACHED */
337	return (FALSE);
338}
339
340/*
341 * XDR unsigned 16-bit integers
342 */
343bool_t
344xdr_uint16_t(XDR *xdrs, uint16_t *uint16_p)
345{
346	u_long l;
347
348	switch (xdrs->x_op) {
349
350	case XDR_ENCODE:
351		l = (u_long) *uint16_p;
352		return (XDR_PUTLONG(xdrs, (long *)&l));
353
354	case XDR_DECODE:
355		if (!XDR_GETLONG(xdrs, (long *)&l)) {
356			return (FALSE);
357		}
358		*uint16_p = (uint16_t) l;
359		return (TRUE);
360
361	case XDR_FREE:
362		return (TRUE);
363	}
364	/* NOTREACHED */
365	return (FALSE);
366}
367
368
369/*
370 * XDR a char
371 */
372bool_t
373xdr_char(XDR *xdrs, char *cp)
374{
375	int i;
376
377	i = (*cp);
378	if (!xdr_int(xdrs, &i)) {
379		return (FALSE);
380	}
381	*cp = i;
382	return (TRUE);
383}
384
385/*
386 * XDR an unsigned char
387 */
388bool_t
389xdr_u_char(XDR *xdrs, u_char *cp)
390{
391	u_int u;
392
393	u = (*cp);
394	if (!xdr_u_int(xdrs, &u)) {
395		return (FALSE);
396	}
397	*cp = u;
398	return (TRUE);
399}
400
401/*
402 * XDR booleans
403 */
404bool_t
405xdr_bool(XDR *xdrs, bool_t *bp)
406{
407	long lb;
408
409	switch (xdrs->x_op) {
410
411	case XDR_ENCODE:
412		lb = *bp ? XDR_TRUE : XDR_FALSE;
413		return (XDR_PUTLONG(xdrs, &lb));
414
415	case XDR_DECODE:
416		if (!XDR_GETLONG(xdrs, &lb)) {
417			return (FALSE);
418		}
419		*bp = (lb == XDR_FALSE) ? FALSE : TRUE;
420		return (TRUE);
421
422	case XDR_FREE:
423		return (TRUE);
424	}
425	/* NOTREACHED */
426	return (FALSE);
427}
428
429/*
430 * XDR enumerations
431 */
432bool_t
433xdr_enum(XDR *xdrs, enum_t *ep)
434{
435	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */
436
437	/*
438	 * enums are treated as ints
439	 */
440	/* LINTED */ if (sizeof (enum sizecheck) == sizeof (long)) {
441		return (xdr_long(xdrs, (long *)(void *)ep));
442	} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (int)) {
443		return (xdr_int(xdrs, (int *)(void *)ep));
444	} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (short)) {
445		return (xdr_short(xdrs, (short *)(void *)ep));
446	} else {
447		return (FALSE);
448	}
449}
450
451/*
452 * XDR opaque data
453 * Allows the specification of a fixed size sequence of opaque bytes.
454 * cp points to the opaque object and cnt gives the byte length.
455 */
456bool_t
457xdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt)
458{
459	u_int rndup;
460	static int crud[BYTES_PER_XDR_UNIT];
461
462	/*
463	 * if no data we are done
464	 */
465	if (cnt == 0)
466		return (TRUE);
467
468	/*
469	 * round byte count to full xdr units
470	 */
471	rndup = cnt % BYTES_PER_XDR_UNIT;
472	if (rndup > 0)
473		rndup = BYTES_PER_XDR_UNIT - rndup;
474
475	if (xdrs->x_op == XDR_DECODE) {
476		if (!XDR_GETBYTES(xdrs, cp, cnt)) {
477			return (FALSE);
478		}
479		if (rndup == 0)
480			return (TRUE);
481		return (XDR_GETBYTES(xdrs, (caddr_t)(void *)crud, rndup));
482	}
483
484	if (xdrs->x_op == XDR_ENCODE) {
485		if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
486			return (FALSE);
487		}
488		if (rndup == 0)
489			return (TRUE);
490		return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
491	}
492
493	if (xdrs->x_op == XDR_FREE) {
494		return (TRUE);
495	}
496
497	return (FALSE);
498}
499
500/*
501 * XDR counted bytes
502 * *cpp is a pointer to the bytes, *sizep is the count.
503 * If *cpp is NULL maxsize bytes are allocated
504 */
505bool_t
506xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
507{
508	char *sp = *cpp;  /* sp is the actual string pointer */
509	u_int nodesize;
510	bool_t ret, allocated = FALSE;
511
512	/*
513	 * first deal with the length since xdr bytes are counted
514	 */
515	if (! xdr_u_int(xdrs, sizep)) {
516		return (FALSE);
517	}
518	nodesize = *sizep;
519	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
520		return (FALSE);
521	}
522
523	/*
524	 * now deal with the actual bytes
525	 */
526	switch (xdrs->x_op) {
527
528	case XDR_DECODE:
529		if (nodesize == 0) {
530			return (TRUE);
531		}
532		if (sp == NULL) {
533			*cpp = sp = mem_alloc(nodesize);
534			allocated = TRUE;
535		}
536		if (sp == NULL) {
537			printf("xdr_bytes: out of memory");
538			return (FALSE);
539		}
540		/* FALLTHROUGH */
541
542	case XDR_ENCODE:
543		ret = xdr_opaque(xdrs, sp, nodesize);
544		if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
545			if (allocated == TRUE) {
546				mem_free(sp, nodesize);
547				*cpp = NULL;
548			}
549		}
550		return (ret);
551
552	case XDR_FREE:
553		if (sp != NULL) {
554			mem_free(sp, nodesize);
555			*cpp = NULL;
556		}
557		return (TRUE);
558	}
559	/* NOTREACHED */
560	return (FALSE);
561}
562
563/*
564 * Implemented here due to commonality of the object.
565 */
566bool_t
567xdr_netobj(XDR *xdrs, struct netobj *np)
568{
569
570	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
571}
572
573/*
574 * XDR a descriminated union
575 * Support routine for discriminated unions.
576 * You create an array of xdrdiscrim structures, terminated with
577 * an entry with a null procedure pointer.  The routine gets
578 * the discriminant value and then searches the array of xdrdiscrims
579 * looking for that value.  It calls the procedure given in the xdrdiscrim
580 * to handle the discriminant.  If there is no specific routine a default
581 * routine may be called.
582 * If there is no specific or default routine an error is returned.
583 */
584bool_t
585xdr_union(XDR *xdrs,
586    enum_t *dscmp,		/* enum to decide which arm to work on */
587    char *unp,				/* the union itself */
588    const struct xdr_discrim *choices,	/* [value, xdr proc] for each arm */
589    xdrproc_t dfault)			/* default xdr routine */
590{
591	enum_t dscm;
592
593	/*
594	 * we deal with the discriminator;  it's an enum
595	 */
596	if (! xdr_enum(xdrs, dscmp)) {
597		return (FALSE);
598	}
599	dscm = *dscmp;
600
601	/*
602	 * search choices for a value that matches the discriminator.
603	 * if we find one, execute the xdr routine for that value.
604	 */
605	for (; choices->proc != NULL_xdrproc_t; choices++) {
606		if (choices->value == dscm)
607			return ((*(choices->proc))(xdrs, unp));
608	}
609
610	/*
611	 * no match - execute the default xdr routine if there is one
612	 */
613	return ((dfault == NULL_xdrproc_t) ? FALSE :
614	    (*dfault)(xdrs, unp));
615}
616
617
618/*
619 * Non-portable xdr primitives.
620 * Care should be taken when moving these routines to new architectures.
621 */
622
623
624/*
625 * XDR null terminated ASCII strings
626 * xdr_string deals with "C strings" - arrays of bytes that are
627 * terminated by a NULL character.  The parameter cpp references a
628 * pointer to storage; If the pointer is null, then the necessary
629 * storage is allocated.  The last parameter is the max allowed length
630 * of the string as specified by a protocol.
631 */
632bool_t
633xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
634{
635	char *sp = *cpp;  /* sp is the actual string pointer */
636	u_int size;
637	u_int nodesize;
638	bool_t ret, allocated = FALSE;
639
640	/*
641	 * first deal with the length since xdr strings are counted-strings
642	 */
643	switch (xdrs->x_op) {
644	case XDR_FREE:
645		if (sp == NULL) {
646			return(TRUE);	/* already free */
647		}
648		/* FALLTHROUGH */
649	case XDR_ENCODE:
650		size = strlen(sp);
651		break;
652	case XDR_DECODE:
653		break;
654	}
655	if (! xdr_u_int(xdrs, &size)) {
656		return (FALSE);
657	}
658	if (size > maxsize) {
659		return (FALSE);
660	}
661	nodesize = size + 1;
662
663	/*
664	 * now deal with the actual bytes
665	 */
666	switch (xdrs->x_op) {
667
668	case XDR_DECODE:
669		if (nodesize == 0) {
670			return (TRUE);
671		}
672		if (sp == NULL) {
673			*cpp = sp = mem_alloc(nodesize);
674			allocated = TRUE;
675		}
676		if (sp == NULL) {
677			printf("xdr_string: out of memory");
678			return (FALSE);
679		}
680		sp[size] = 0;
681		/* FALLTHROUGH */
682
683	case XDR_ENCODE:
684		ret = xdr_opaque(xdrs, sp, size);
685		if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
686			if (allocated == TRUE) {
687				mem_free(sp, nodesize);
688				*cpp = NULL;
689			}
690		}
691		return (ret);
692
693	case XDR_FREE:
694		mem_free(sp, nodesize);
695		*cpp = NULL;
696		return (TRUE);
697	}
698	/* NOTREACHED */
699	return (FALSE);
700}
701
702/*
703 * Wrapper for xdr_string that can be called directly from
704 * routines like clnt_call
705 */
706bool_t
707xdr_wrapstring(XDR *xdrs, char **cpp)
708{
709	return xdr_string(xdrs, cpp, RPC_MAXDATASIZE);
710}
711
712/*
713 * NOTE: xdr_hyper(), xdr_u_hyper(), xdr_longlong_t(), and xdr_u_longlong_t()
714 * are in the "non-portable" section because they require that a `long long'
715 * be a 64-bit type.
716 *
717 *	--thorpej@netbsd.org, November 30, 1999
718 */
719
720/*
721 * XDR 64-bit integers
722 */
723bool_t
724xdr_int64_t(XDR *xdrs, int64_t *llp)
725{
726	u_long ul[2];
727
728	switch (xdrs->x_op) {
729	case XDR_ENCODE:
730		ul[0] = (u_long)((uint64_t)*llp >> 32) & 0xffffffff;
731		ul[1] = (u_long)((uint64_t)*llp) & 0xffffffff;
732		if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
733			return (FALSE);
734		return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
735	case XDR_DECODE:
736		if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
737			return (FALSE);
738		if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
739			return (FALSE);
740		*llp = (int64_t)
741		    (((uint64_t)ul[0] << 32) | ((uint64_t)ul[1]));
742		return (TRUE);
743	case XDR_FREE:
744		return (TRUE);
745	}
746	/* NOTREACHED */
747	return (FALSE);
748}
749
750
751/*
752 * XDR unsigned 64-bit integers
753 */
754bool_t
755xdr_uint64_t(XDR *xdrs, uint64_t *ullp)
756{
757	u_long ul[2];
758
759	switch (xdrs->x_op) {
760	case XDR_ENCODE:
761		ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
762		ul[1] = (u_long)(*ullp) & 0xffffffff;
763		if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
764			return (FALSE);
765		return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
766	case XDR_DECODE:
767		if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
768			return (FALSE);
769		if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
770			return (FALSE);
771		*ullp = (uint64_t)
772		    (((uint64_t)ul[0] << 32) | ((uint64_t)ul[1]));
773		return (TRUE);
774	case XDR_FREE:
775		return (TRUE);
776	}
777	/* NOTREACHED */
778	return (FALSE);
779}
780
781
782/*
783 * XDR hypers
784 */
785bool_t
786xdr_hyper(XDR *xdrs, longlong_t *llp)
787{
788
789	/*
790	 * Don't bother open-coding this; it's a fair amount of code.  Just
791	 * call xdr_int64_t().
792	 */
793	return (xdr_int64_t(xdrs, (int64_t *)llp));
794}
795
796
797/*
798 * XDR unsigned hypers
799 */
800bool_t
801xdr_u_hyper(XDR *xdrs, u_longlong_t *ullp)
802{
803
804	/*
805	 * Don't bother open-coding this; it's a fair amount of code.  Just
806	 * call xdr_uint64_t().
807	 */
808	return (xdr_uint64_t(xdrs, (uint64_t *)ullp));
809}
810
811
812/*
813 * XDR longlong_t's
814 */
815bool_t
816xdr_longlong_t(XDR *xdrs, longlong_t *llp)
817{
818
819	/*
820	 * Don't bother open-coding this; it's a fair amount of code.  Just
821	 * call xdr_int64_t().
822	 */
823	return (xdr_int64_t(xdrs, (int64_t *)llp));
824}
825
826
827/*
828 * XDR u_longlong_t's
829 */
830bool_t
831xdr_u_longlong_t(XDR *xdrs, u_longlong_t *ullp)
832{
833
834	/*
835	 * Don't bother open-coding this; it's a fair amount of code.  Just
836	 * call xdr_uint64_t().
837	 */
838	return (xdr_uint64_t(xdrs, (uint64_t *)ullp));
839}
840
841/*
842 * Kernel module glue
843 */
844static int
845xdr_modevent(module_t mod, int type, void *data)
846{
847
848        return (0);
849}
850static moduledata_t xdr_mod = {
851        "xdr",
852        xdr_modevent,
853        NULL,
854};
855DECLARE_MODULE(xdr, xdr_mod, SI_SUB_VFS, SI_ORDER_ANY);
856MODULE_VERSION(xdr, 1);
857