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