1177633Sdfr/*	$NetBSD: xdr.c,v 1.22 2000/07/06 03:10:35 christos Exp $	*/
2177633Sdfr
3177633Sdfr/*
4177633Sdfr * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5177633Sdfr * unrestricted use provided that this legend is included on all tape
6177633Sdfr * media and as a part of the software program in whole or part.  Users
7177633Sdfr * may copy or modify Sun RPC without charge, but are not authorized
8177633Sdfr * to license or distribute it to anyone else except as part of a product or
9177633Sdfr * program developed by the user.
10177633Sdfr *
11177633Sdfr * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12177633Sdfr * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13177633Sdfr * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14177633Sdfr *
15177633Sdfr * Sun RPC is provided with no support and without any obligation on the
16177633Sdfr * part of Sun Microsystems, Inc. to assist in its use, correction,
17177633Sdfr * modification or enhancement.
18177633Sdfr *
19177633Sdfr * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20177633Sdfr * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21177633Sdfr * OR ANY PART THEREOF.
22177633Sdfr *
23177633Sdfr * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24177633Sdfr * or profits or other special, indirect and consequential damages, even if
25177633Sdfr * Sun has been advised of the possibility of such damages.
26177633Sdfr *
27177633Sdfr * Sun Microsystems, Inc.
28177633Sdfr * 2550 Garcia Avenue
29177633Sdfr * Mountain View, California  94043
30177633Sdfr */
31177633Sdfr
32177633Sdfr#if defined(LIBC_SCCS) && !defined(lint)
33177633Sdfrstatic char *sccsid2 = "@(#)xdr.c 1.35 87/08/12";
34177633Sdfrstatic char *sccsid = "@(#)xdr.c	2.1 88/07/29 4.0 RPCSRC";
35177633Sdfr#endif
36177633Sdfr#include <sys/cdefs.h>
37177633Sdfr__FBSDID("$FreeBSD$");
38177633Sdfr
39177633Sdfr/*
40177633Sdfr * xdr.c, Generic XDR routines implementation.
41177633Sdfr *
42177633Sdfr * Copyright (C) 1986, Sun Microsystems, Inc.
43177633Sdfr *
44177633Sdfr * These are the "generic" xdr routines used to serialize and de-serialize
45177633Sdfr * most common data items.  See xdr.h for more info on the interface to
46177633Sdfr * xdr.
47177633Sdfr */
48177633Sdfr
49177633Sdfr#include <sys/param.h>
50177633Sdfr#include <sys/systm.h>
51177633Sdfr#include <sys/kernel.h>
52177633Sdfr#include <sys/malloc.h>
53177633Sdfr
54177633Sdfr#include <rpc/types.h>
55177633Sdfr#include <rpc/xdr.h>
56177633Sdfr
57177633Sdfrtypedef quad_t          longlong_t;     /* ANSI long long type */
58177633Sdfrtypedef u_quad_t        u_longlong_t;   /* ANSI unsigned long long type */
59177633Sdfr
60177633Sdfr/*
61177633Sdfr * constants specific to the xdr "protocol"
62177633Sdfr */
63177633Sdfr#define XDR_FALSE	((long) 0)
64177633Sdfr#define XDR_TRUE	((long) 1)
65177633Sdfr#define LASTUNSIGNED	((u_int) 0-1)
66177633Sdfr
67177633Sdfr/*
68177633Sdfr * for unit alignment
69177633Sdfr */
70177633Sdfrstatic const char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
71177633Sdfr
72177633Sdfr/*
73177633Sdfr * Free a data structure using XDR
74177633Sdfr * Not a filter, but a convenient utility nonetheless
75177633Sdfr */
76177633Sdfrvoid
77177633Sdfrxdr_free(xdrproc_t proc, void *objp)
78177633Sdfr{
79177633Sdfr	XDR x;
80177633Sdfr
81177633Sdfr	x.x_op = XDR_FREE;
82177633Sdfr	(*proc)(&x, objp);
83177633Sdfr}
84177633Sdfr
85177633Sdfr/*
86177633Sdfr * XDR nothing
87177633Sdfr */
88177633Sdfrbool_t
89177633Sdfrxdr_void(void)
90177633Sdfr{
91177633Sdfr
92177633Sdfr	return (TRUE);
93177633Sdfr}
94177633Sdfr
95177633Sdfr
96177633Sdfr/*
97177633Sdfr * XDR integers
98177633Sdfr */
99177633Sdfrbool_t
100177633Sdfrxdr_int(XDR *xdrs, int *ip)
101177633Sdfr{
102177633Sdfr	long l;
103177633Sdfr
104177633Sdfr	switch (xdrs->x_op) {
105177633Sdfr
106177633Sdfr	case XDR_ENCODE:
107177633Sdfr		l = (long) *ip;
108177633Sdfr		return (XDR_PUTLONG(xdrs, &l));
109177633Sdfr
110177633Sdfr	case XDR_DECODE:
111177633Sdfr		if (!XDR_GETLONG(xdrs, &l)) {
112177633Sdfr			return (FALSE);
113177633Sdfr		}
114177633Sdfr		*ip = (int) l;
115177633Sdfr		return (TRUE);
116177633Sdfr
117177633Sdfr	case XDR_FREE:
118177633Sdfr		return (TRUE);
119177633Sdfr	}
120177633Sdfr	/* NOTREACHED */
121177633Sdfr	return (FALSE);
122177633Sdfr}
123177633Sdfr
124177633Sdfr/*
125177633Sdfr * XDR unsigned integers
126177633Sdfr */
127177633Sdfrbool_t
128177633Sdfrxdr_u_int(XDR *xdrs, u_int *up)
129177633Sdfr{
130177633Sdfr	u_long l;
131177633Sdfr
132177633Sdfr	switch (xdrs->x_op) {
133177633Sdfr
134177633Sdfr	case XDR_ENCODE:
135177633Sdfr		l = (u_long) *up;
136177633Sdfr		return (XDR_PUTLONG(xdrs, (long *)&l));
137177633Sdfr
138177633Sdfr	case XDR_DECODE:
139177633Sdfr		if (!XDR_GETLONG(xdrs, (long *)&l)) {
140177633Sdfr			return (FALSE);
141177633Sdfr		}
142177633Sdfr		*up = (u_int) l;
143177633Sdfr		return (TRUE);
144177633Sdfr
145177633Sdfr	case XDR_FREE:
146177633Sdfr		return (TRUE);
147177633Sdfr	}
148177633Sdfr	/* NOTREACHED */
149177633Sdfr	return (FALSE);
150177633Sdfr}
151177633Sdfr
152177633Sdfr
153177633Sdfr/*
154177633Sdfr * XDR long integers
155177633Sdfr * same as xdr_u_long - open coded to save a proc call!
156177633Sdfr */
157177633Sdfrbool_t
158177633Sdfrxdr_long(XDR *xdrs, long *lp)
159177633Sdfr{
160177633Sdfr	switch (xdrs->x_op) {
161177633Sdfr	case XDR_ENCODE:
162177633Sdfr		return (XDR_PUTLONG(xdrs, lp));
163177633Sdfr	case XDR_DECODE:
164177633Sdfr		return (XDR_GETLONG(xdrs, lp));
165177633Sdfr	case XDR_FREE:
166177633Sdfr		return (TRUE);
167177633Sdfr	}
168177633Sdfr	/* NOTREACHED */
169177633Sdfr	return (FALSE);
170177633Sdfr}
171177633Sdfr
172177633Sdfr/*
173177633Sdfr * XDR unsigned long integers
174177633Sdfr * same as xdr_long - open coded to save a proc call!
175177633Sdfr */
176177633Sdfrbool_t
177177633Sdfrxdr_u_long(XDR *xdrs, u_long *ulp)
178177633Sdfr{
179177633Sdfr	switch (xdrs->x_op) {
180177633Sdfr	case XDR_ENCODE:
181177633Sdfr		return (XDR_PUTLONG(xdrs, (long *)ulp));
182177633Sdfr	case XDR_DECODE:
183177633Sdfr		return (XDR_GETLONG(xdrs, (long *)ulp));
184177633Sdfr	case XDR_FREE:
185177633Sdfr		return (TRUE);
186177633Sdfr	}
187177633Sdfr	/* NOTREACHED */
188177633Sdfr	return (FALSE);
189177633Sdfr}
190177633Sdfr
191177633Sdfr
192177633Sdfr/*
193177633Sdfr * XDR 32-bit integers
194177633Sdfr * same as xdr_uint32_t - open coded to save a proc call!
195177633Sdfr */
196177633Sdfrbool_t
197177633Sdfrxdr_int32_t(XDR *xdrs, int32_t *int32_p)
198177633Sdfr{
199177633Sdfr	long l;
200177633Sdfr
201177633Sdfr	switch (xdrs->x_op) {
202177633Sdfr
203177633Sdfr	case XDR_ENCODE:
204177633Sdfr		l = (long) *int32_p;
205177633Sdfr		return (XDR_PUTLONG(xdrs, &l));
206177633Sdfr
207177633Sdfr	case XDR_DECODE:
208177633Sdfr		if (!XDR_GETLONG(xdrs, &l)) {
209177633Sdfr			return (FALSE);
210177633Sdfr		}
211177633Sdfr		*int32_p = (int32_t) l;
212177633Sdfr		return (TRUE);
213177633Sdfr
214177633Sdfr	case XDR_FREE:
215177633Sdfr		return (TRUE);
216177633Sdfr	}
217177633Sdfr	/* NOTREACHED */
218177633Sdfr	return (FALSE);
219177633Sdfr}
220177633Sdfr
221177633Sdfr/*
222177633Sdfr * XDR unsigned 32-bit integers
223177633Sdfr * same as xdr_int32_t - open coded to save a proc call!
224177633Sdfr */
225177633Sdfrbool_t
226177633Sdfrxdr_uint32_t(XDR *xdrs, uint32_t *uint32_p)
227177633Sdfr{
228177633Sdfr	u_long l;
229177633Sdfr
230177633Sdfr	switch (xdrs->x_op) {
231177633Sdfr
232177633Sdfr	case XDR_ENCODE:
233177633Sdfr		l = (u_long) *uint32_p;
234177633Sdfr		return (XDR_PUTLONG(xdrs, (long *)&l));
235177633Sdfr
236177633Sdfr	case XDR_DECODE:
237177633Sdfr		if (!XDR_GETLONG(xdrs, (long *)&l)) {
238177633Sdfr			return (FALSE);
239177633Sdfr		}
240177633Sdfr		*uint32_p = (uint32_t) l;
241177633Sdfr		return (TRUE);
242177633Sdfr
243177633Sdfr	case XDR_FREE:
244177633Sdfr		return (TRUE);
245177633Sdfr	}
246177633Sdfr	/* NOTREACHED */
247177633Sdfr	return (FALSE);
248177633Sdfr}
249177633Sdfr
250177633Sdfr
251177633Sdfr/*
252177633Sdfr * XDR short integers
253177633Sdfr */
254177633Sdfrbool_t
255177633Sdfrxdr_short(XDR *xdrs, short *sp)
256177633Sdfr{
257177633Sdfr	long l;
258177633Sdfr
259177633Sdfr	switch (xdrs->x_op) {
260177633Sdfr
261177633Sdfr	case XDR_ENCODE:
262177633Sdfr		l = (long) *sp;
263177633Sdfr		return (XDR_PUTLONG(xdrs, &l));
264177633Sdfr
265177633Sdfr	case XDR_DECODE:
266177633Sdfr		if (!XDR_GETLONG(xdrs, &l)) {
267177633Sdfr			return (FALSE);
268177633Sdfr		}
269177633Sdfr		*sp = (short) l;
270177633Sdfr		return (TRUE);
271177633Sdfr
272177633Sdfr	case XDR_FREE:
273177633Sdfr		return (TRUE);
274177633Sdfr	}
275177633Sdfr	/* NOTREACHED */
276177633Sdfr	return (FALSE);
277177633Sdfr}
278177633Sdfr
279177633Sdfr/*
280177633Sdfr * XDR unsigned short integers
281177633Sdfr */
282177633Sdfrbool_t
283177633Sdfrxdr_u_short(XDR *xdrs, u_short *usp)
284177633Sdfr{
285177633Sdfr	u_long l;
286177633Sdfr
287177633Sdfr	switch (xdrs->x_op) {
288177633Sdfr
289177633Sdfr	case XDR_ENCODE:
290177633Sdfr		l = (u_long) *usp;
291177633Sdfr		return (XDR_PUTLONG(xdrs, (long *)&l));
292177633Sdfr
293177633Sdfr	case XDR_DECODE:
294177633Sdfr		if (!XDR_GETLONG(xdrs, (long *)&l)) {
295177633Sdfr			return (FALSE);
296177633Sdfr		}
297177633Sdfr		*usp = (u_short) l;
298177633Sdfr		return (TRUE);
299177633Sdfr
300177633Sdfr	case XDR_FREE:
301177633Sdfr		return (TRUE);
302177633Sdfr	}
303177633Sdfr	/* NOTREACHED */
304177633Sdfr	return (FALSE);
305177633Sdfr}
306177633Sdfr
307177633Sdfr
308177633Sdfr/*
309177633Sdfr * XDR 16-bit integers
310177633Sdfr */
311177633Sdfrbool_t
312177633Sdfrxdr_int16_t(XDR *xdrs, int16_t *int16_p)
313177633Sdfr{
314177633Sdfr	long l;
315177633Sdfr
316177633Sdfr	switch (xdrs->x_op) {
317177633Sdfr
318177633Sdfr	case XDR_ENCODE:
319177633Sdfr		l = (long) *int16_p;
320177633Sdfr		return (XDR_PUTLONG(xdrs, &l));
321177633Sdfr
322177633Sdfr	case XDR_DECODE:
323177633Sdfr		if (!XDR_GETLONG(xdrs, &l)) {
324177633Sdfr			return (FALSE);
325177633Sdfr		}
326177633Sdfr		*int16_p = (int16_t) l;
327177633Sdfr		return (TRUE);
328177633Sdfr
329177633Sdfr	case XDR_FREE:
330177633Sdfr		return (TRUE);
331177633Sdfr	}
332177633Sdfr	/* NOTREACHED */
333177633Sdfr	return (FALSE);
334177633Sdfr}
335177633Sdfr
336177633Sdfr/*
337177633Sdfr * XDR unsigned 16-bit integers
338177633Sdfr */
339177633Sdfrbool_t
340177633Sdfrxdr_uint16_t(XDR *xdrs, uint16_t *uint16_p)
341177633Sdfr{
342177633Sdfr	u_long l;
343177633Sdfr
344177633Sdfr	switch (xdrs->x_op) {
345177633Sdfr
346177633Sdfr	case XDR_ENCODE:
347177633Sdfr		l = (u_long) *uint16_p;
348177633Sdfr		return (XDR_PUTLONG(xdrs, (long *)&l));
349177633Sdfr
350177633Sdfr	case XDR_DECODE:
351177633Sdfr		if (!XDR_GETLONG(xdrs, (long *)&l)) {
352177633Sdfr			return (FALSE);
353177633Sdfr		}
354177633Sdfr		*uint16_p = (uint16_t) l;
355177633Sdfr		return (TRUE);
356177633Sdfr
357177633Sdfr	case XDR_FREE:
358177633Sdfr		return (TRUE);
359177633Sdfr	}
360177633Sdfr	/* NOTREACHED */
361177633Sdfr	return (FALSE);
362177633Sdfr}
363177633Sdfr
364177633Sdfr
365177633Sdfr/*
366177633Sdfr * XDR a char
367177633Sdfr */
368177633Sdfrbool_t
369177633Sdfrxdr_char(XDR *xdrs, char *cp)
370177633Sdfr{
371177633Sdfr	int i;
372177633Sdfr
373177633Sdfr	i = (*cp);
374177633Sdfr	if (!xdr_int(xdrs, &i)) {
375177633Sdfr		return (FALSE);
376177633Sdfr	}
377177633Sdfr	*cp = i;
378177633Sdfr	return (TRUE);
379177633Sdfr}
380177633Sdfr
381177633Sdfr/*
382177633Sdfr * XDR an unsigned char
383177633Sdfr */
384177633Sdfrbool_t
385177633Sdfrxdr_u_char(XDR *xdrs, u_char *cp)
386177633Sdfr{
387177633Sdfr	u_int u;
388177633Sdfr
389177633Sdfr	u = (*cp);
390177633Sdfr	if (!xdr_u_int(xdrs, &u)) {
391177633Sdfr		return (FALSE);
392177633Sdfr	}
393177633Sdfr	*cp = u;
394177633Sdfr	return (TRUE);
395177633Sdfr}
396177633Sdfr
397177633Sdfr/*
398177633Sdfr * XDR booleans
399177633Sdfr */
400177633Sdfrbool_t
401177633Sdfrxdr_bool(XDR *xdrs, bool_t *bp)
402177633Sdfr{
403177633Sdfr	long lb;
404177633Sdfr
405177633Sdfr	switch (xdrs->x_op) {
406177633Sdfr
407177633Sdfr	case XDR_ENCODE:
408177633Sdfr		lb = *bp ? XDR_TRUE : XDR_FALSE;
409177633Sdfr		return (XDR_PUTLONG(xdrs, &lb));
410177633Sdfr
411177633Sdfr	case XDR_DECODE:
412177633Sdfr		if (!XDR_GETLONG(xdrs, &lb)) {
413177633Sdfr			return (FALSE);
414177633Sdfr		}
415177633Sdfr		*bp = (lb == XDR_FALSE) ? FALSE : TRUE;
416177633Sdfr		return (TRUE);
417177633Sdfr
418177633Sdfr	case XDR_FREE:
419177633Sdfr		return (TRUE);
420177633Sdfr	}
421177633Sdfr	/* NOTREACHED */
422177633Sdfr	return (FALSE);
423177633Sdfr}
424177633Sdfr
425177633Sdfr/*
426177633Sdfr * XDR enumerations
427177633Sdfr */
428177633Sdfrbool_t
429177633Sdfrxdr_enum(XDR *xdrs, enum_t *ep)
430177633Sdfr{
431177633Sdfr	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */
432177633Sdfr
433177633Sdfr	/*
434177633Sdfr	 * enums are treated as ints
435177633Sdfr	 */
436177633Sdfr	/* LINTED */ if (sizeof (enum sizecheck) == sizeof (long)) {
437177633Sdfr		return (xdr_long(xdrs, (long *)(void *)ep));
438177633Sdfr	} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (int)) {
439177633Sdfr		return (xdr_int(xdrs, (int *)(void *)ep));
440177633Sdfr	} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (short)) {
441177633Sdfr		return (xdr_short(xdrs, (short *)(void *)ep));
442177633Sdfr	} else {
443177633Sdfr		return (FALSE);
444177633Sdfr	}
445177633Sdfr}
446177633Sdfr
447177633Sdfr/*
448177633Sdfr * XDR opaque data
449177633Sdfr * Allows the specification of a fixed size sequence of opaque bytes.
450177633Sdfr * cp points to the opaque object and cnt gives the byte length.
451177633Sdfr */
452177633Sdfrbool_t
453177633Sdfrxdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt)
454177633Sdfr{
455177633Sdfr	u_int rndup;
456177633Sdfr	static int crud[BYTES_PER_XDR_UNIT];
457177633Sdfr
458177633Sdfr	/*
459177633Sdfr	 * if no data we are done
460177633Sdfr	 */
461177633Sdfr	if (cnt == 0)
462177633Sdfr		return (TRUE);
463177633Sdfr
464177633Sdfr	/*
465177633Sdfr	 * round byte count to full xdr units
466177633Sdfr	 */
467177633Sdfr	rndup = cnt % BYTES_PER_XDR_UNIT;
468177633Sdfr	if (rndup > 0)
469177633Sdfr		rndup = BYTES_PER_XDR_UNIT - rndup;
470177633Sdfr
471177633Sdfr	if (xdrs->x_op == XDR_DECODE) {
472177633Sdfr		if (!XDR_GETBYTES(xdrs, cp, cnt)) {
473177633Sdfr			return (FALSE);
474177633Sdfr		}
475177633Sdfr		if (rndup == 0)
476177633Sdfr			return (TRUE);
477177633Sdfr		return (XDR_GETBYTES(xdrs, (caddr_t)(void *)crud, rndup));
478177633Sdfr	}
479177633Sdfr
480177633Sdfr	if (xdrs->x_op == XDR_ENCODE) {
481177633Sdfr		if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
482177633Sdfr			return (FALSE);
483177633Sdfr		}
484177633Sdfr		if (rndup == 0)
485177633Sdfr			return (TRUE);
486177633Sdfr		return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
487177633Sdfr	}
488177633Sdfr
489177633Sdfr	if (xdrs->x_op == XDR_FREE) {
490177633Sdfr		return (TRUE);
491177633Sdfr	}
492177633Sdfr
493177633Sdfr	return (FALSE);
494177633Sdfr}
495177633Sdfr
496177633Sdfr/*
497177633Sdfr * XDR counted bytes
498177633Sdfr * *cpp is a pointer to the bytes, *sizep is the count.
499177633Sdfr * If *cpp is NULL maxsize bytes are allocated
500177633Sdfr */
501177633Sdfrbool_t
502177633Sdfrxdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
503177633Sdfr{
504177633Sdfr	char *sp = *cpp;  /* sp is the actual string pointer */
505177633Sdfr	u_int nodesize;
506177633Sdfr
507177633Sdfr	/*
508177633Sdfr	 * first deal with the length since xdr bytes are counted
509177633Sdfr	 */
510177633Sdfr	if (! xdr_u_int(xdrs, sizep)) {
511177633Sdfr		return (FALSE);
512177633Sdfr	}
513177633Sdfr	nodesize = *sizep;
514177633Sdfr	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
515177633Sdfr		return (FALSE);
516177633Sdfr	}
517177633Sdfr
518177633Sdfr	/*
519177633Sdfr	 * now deal with the actual bytes
520177633Sdfr	 */
521177633Sdfr	switch (xdrs->x_op) {
522177633Sdfr
523177633Sdfr	case XDR_DECODE:
524177633Sdfr		if (nodesize == 0) {
525177633Sdfr			return (TRUE);
526177633Sdfr		}
527177633Sdfr		if (sp == NULL) {
528177633Sdfr			*cpp = sp = mem_alloc(nodesize);
529177633Sdfr		}
530177633Sdfr		if (sp == NULL) {
531177633Sdfr			printf("xdr_bytes: out of memory");
532177633Sdfr			return (FALSE);
533177633Sdfr		}
534177633Sdfr		/* FALLTHROUGH */
535177633Sdfr
536177633Sdfr	case XDR_ENCODE:
537177633Sdfr		return (xdr_opaque(xdrs, sp, nodesize));
538177633Sdfr
539177633Sdfr	case XDR_FREE:
540177633Sdfr		if (sp != NULL) {
541177633Sdfr			mem_free(sp, nodesize);
542177633Sdfr			*cpp = NULL;
543177633Sdfr		}
544177633Sdfr		return (TRUE);
545177633Sdfr	}
546177633Sdfr	/* NOTREACHED */
547177633Sdfr	return (FALSE);
548177633Sdfr}
549177633Sdfr
550177633Sdfr/*
551177633Sdfr * Implemented here due to commonality of the object.
552177633Sdfr */
553177633Sdfrbool_t
554177633Sdfrxdr_netobj(XDR *xdrs, struct netobj *np)
555177633Sdfr{
556177633Sdfr
557177633Sdfr	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
558177633Sdfr}
559177633Sdfr
560177633Sdfr/*
561177633Sdfr * XDR a descriminated union
562177633Sdfr * Support routine for discriminated unions.
563177633Sdfr * You create an array of xdrdiscrim structures, terminated with
564177633Sdfr * an entry with a null procedure pointer.  The routine gets
565177633Sdfr * the discriminant value and then searches the array of xdrdiscrims
566177633Sdfr * looking for that value.  It calls the procedure given in the xdrdiscrim
567177633Sdfr * to handle the discriminant.  If there is no specific routine a default
568177633Sdfr * routine may be called.
569177633Sdfr * If there is no specific or default routine an error is returned.
570177633Sdfr */
571177633Sdfrbool_t
572177633Sdfrxdr_union(XDR *xdrs,
573177633Sdfr    enum_t *dscmp,		/* enum to decide which arm to work on */
574177633Sdfr    char *unp,				/* the union itself */
575177633Sdfr    const struct xdr_discrim *choices,	/* [value, xdr proc] for each arm */
576177633Sdfr    xdrproc_t dfault)			/* default xdr routine */
577177633Sdfr{
578177633Sdfr	enum_t dscm;
579177633Sdfr
580177633Sdfr	/*
581177633Sdfr	 * we deal with the discriminator;  it's an enum
582177633Sdfr	 */
583177633Sdfr	if (! xdr_enum(xdrs, dscmp)) {
584177633Sdfr		return (FALSE);
585177633Sdfr	}
586177633Sdfr	dscm = *dscmp;
587177633Sdfr
588177633Sdfr	/*
589177633Sdfr	 * search choices for a value that matches the discriminator.
590177633Sdfr	 * if we find one, execute the xdr routine for that value.
591177633Sdfr	 */
592177633Sdfr	for (; choices->proc != NULL_xdrproc_t; choices++) {
593177633Sdfr		if (choices->value == dscm)
594177633Sdfr			return ((*(choices->proc))(xdrs, unp));
595177633Sdfr	}
596177633Sdfr
597177633Sdfr	/*
598177633Sdfr	 * no match - execute the default xdr routine if there is one
599177633Sdfr	 */
600177633Sdfr	return ((dfault == NULL_xdrproc_t) ? FALSE :
601177633Sdfr	    (*dfault)(xdrs, unp));
602177633Sdfr}
603177633Sdfr
604177633Sdfr
605177633Sdfr/*
606177633Sdfr * Non-portable xdr primitives.
607177633Sdfr * Care should be taken when moving these routines to new architectures.
608177633Sdfr */
609177633Sdfr
610177633Sdfr
611177633Sdfr/*
612177633Sdfr * XDR null terminated ASCII strings
613177633Sdfr * xdr_string deals with "C strings" - arrays of bytes that are
614177633Sdfr * terminated by a NULL character.  The parameter cpp references a
615177633Sdfr * pointer to storage; If the pointer is null, then the necessary
616177633Sdfr * storage is allocated.  The last parameter is the max allowed length
617177633Sdfr * of the string as specified by a protocol.
618177633Sdfr */
619177633Sdfrbool_t
620177633Sdfrxdr_string(XDR *xdrs, char **cpp, u_int maxsize)
621177633Sdfr{
622177633Sdfr	char *sp = *cpp;  /* sp is the actual string pointer */
623177633Sdfr	u_int size;
624177633Sdfr	u_int nodesize;
625177633Sdfr
626177633Sdfr	/*
627177633Sdfr	 * first deal with the length since xdr strings are counted-strings
628177633Sdfr	 */
629177633Sdfr	switch (xdrs->x_op) {
630177633Sdfr	case XDR_FREE:
631177633Sdfr		if (sp == NULL) {
632177633Sdfr			return(TRUE);	/* already free */
633177633Sdfr		}
634177633Sdfr		/* FALLTHROUGH */
635177633Sdfr	case XDR_ENCODE:
636177633Sdfr		size = strlen(sp);
637177633Sdfr		break;
638177633Sdfr	case XDR_DECODE:
639177633Sdfr		break;
640177633Sdfr	}
641177633Sdfr	if (! xdr_u_int(xdrs, &size)) {
642177633Sdfr		return (FALSE);
643177633Sdfr	}
644177633Sdfr	if (size > maxsize) {
645177633Sdfr		return (FALSE);
646177633Sdfr	}
647177633Sdfr	nodesize = size + 1;
648177633Sdfr
649177633Sdfr	/*
650177633Sdfr	 * now deal with the actual bytes
651177633Sdfr	 */
652177633Sdfr	switch (xdrs->x_op) {
653177633Sdfr
654177633Sdfr	case XDR_DECODE:
655177633Sdfr		if (nodesize == 0) {
656177633Sdfr			return (TRUE);
657177633Sdfr		}
658177633Sdfr		if (sp == NULL)
659177633Sdfr			*cpp = sp = mem_alloc(nodesize);
660177633Sdfr		if (sp == NULL) {
661177633Sdfr			printf("xdr_string: out of memory");
662177633Sdfr			return (FALSE);
663177633Sdfr		}
664177633Sdfr		sp[size] = 0;
665177633Sdfr		/* FALLTHROUGH */
666177633Sdfr
667177633Sdfr	case XDR_ENCODE:
668177633Sdfr		return (xdr_opaque(xdrs, sp, size));
669177633Sdfr
670177633Sdfr	case XDR_FREE:
671177633Sdfr		mem_free(sp, nodesize);
672177633Sdfr		*cpp = NULL;
673177633Sdfr		return (TRUE);
674177633Sdfr	}
675177633Sdfr	/* NOTREACHED */
676177633Sdfr	return (FALSE);
677177633Sdfr}
678177633Sdfr
679177633Sdfr/*
680177633Sdfr * Wrapper for xdr_string that can be called directly from
681177633Sdfr * routines like clnt_call
682177633Sdfr */
683177633Sdfrbool_t
684177633Sdfrxdr_wrapstring(XDR *xdrs, char **cpp)
685177633Sdfr{
686177633Sdfr	return xdr_string(xdrs, cpp, LASTUNSIGNED);
687177633Sdfr}
688177633Sdfr
689177633Sdfr/*
690177633Sdfr * NOTE: xdr_hyper(), xdr_u_hyper(), xdr_longlong_t(), and xdr_u_longlong_t()
691177633Sdfr * are in the "non-portable" section because they require that a `long long'
692177633Sdfr * be a 64-bit type.
693177633Sdfr *
694177633Sdfr *	--thorpej@netbsd.org, November 30, 1999
695177633Sdfr */
696177633Sdfr
697177633Sdfr/*
698177633Sdfr * XDR 64-bit integers
699177633Sdfr */
700177633Sdfrbool_t
701177633Sdfrxdr_int64_t(XDR *xdrs, int64_t *llp)
702177633Sdfr{
703177633Sdfr	u_long ul[2];
704177633Sdfr
705177633Sdfr	switch (xdrs->x_op) {
706177633Sdfr	case XDR_ENCODE:
707177633Sdfr		ul[0] = (u_long)((uint64_t)*llp >> 32) & 0xffffffff;
708177633Sdfr		ul[1] = (u_long)((uint64_t)*llp) & 0xffffffff;
709177633Sdfr		if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
710177633Sdfr			return (FALSE);
711177633Sdfr		return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
712177633Sdfr	case XDR_DECODE:
713177633Sdfr		if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
714177633Sdfr			return (FALSE);
715177633Sdfr		if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
716177633Sdfr			return (FALSE);
717177633Sdfr		*llp = (int64_t)
718177633Sdfr		    (((uint64_t)ul[0] << 32) | ((uint64_t)ul[1]));
719177633Sdfr		return (TRUE);
720177633Sdfr	case XDR_FREE:
721177633Sdfr		return (TRUE);
722177633Sdfr	}
723177633Sdfr	/* NOTREACHED */
724177633Sdfr	return (FALSE);
725177633Sdfr}
726177633Sdfr
727177633Sdfr
728177633Sdfr/*
729177633Sdfr * XDR unsigned 64-bit integers
730177633Sdfr */
731177633Sdfrbool_t
732177633Sdfrxdr_uint64_t(XDR *xdrs, uint64_t *ullp)
733177633Sdfr{
734177633Sdfr	u_long ul[2];
735177633Sdfr
736177633Sdfr	switch (xdrs->x_op) {
737177633Sdfr	case XDR_ENCODE:
738177633Sdfr		ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
739177633Sdfr		ul[1] = (u_long)(*ullp) & 0xffffffff;
740177633Sdfr		if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
741177633Sdfr			return (FALSE);
742177633Sdfr		return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
743177633Sdfr	case XDR_DECODE:
744177633Sdfr		if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
745177633Sdfr			return (FALSE);
746177633Sdfr		if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
747177633Sdfr			return (FALSE);
748177633Sdfr		*ullp = (uint64_t)
749177633Sdfr		    (((uint64_t)ul[0] << 32) | ((uint64_t)ul[1]));
750177633Sdfr		return (TRUE);
751177633Sdfr	case XDR_FREE:
752177633Sdfr		return (TRUE);
753177633Sdfr	}
754177633Sdfr	/* NOTREACHED */
755177633Sdfr	return (FALSE);
756177633Sdfr}
757177633Sdfr
758177633Sdfr
759177633Sdfr/*
760177633Sdfr * XDR hypers
761177633Sdfr */
762177633Sdfrbool_t
763177633Sdfrxdr_hyper(XDR *xdrs, longlong_t *llp)
764177633Sdfr{
765177633Sdfr
766177633Sdfr	/*
767177633Sdfr	 * Don't bother open-coding this; it's a fair amount of code.  Just
768177633Sdfr	 * call xdr_int64_t().
769177633Sdfr	 */
770177633Sdfr	return (xdr_int64_t(xdrs, (int64_t *)llp));
771177633Sdfr}
772177633Sdfr
773177633Sdfr
774177633Sdfr/*
775177633Sdfr * XDR unsigned hypers
776177633Sdfr */
777177633Sdfrbool_t
778177633Sdfrxdr_u_hyper(XDR *xdrs, u_longlong_t *ullp)
779177633Sdfr{
780177633Sdfr
781177633Sdfr	/*
782177633Sdfr	 * Don't bother open-coding this; it's a fair amount of code.  Just
783177633Sdfr	 * call xdr_uint64_t().
784177633Sdfr	 */
785177633Sdfr	return (xdr_uint64_t(xdrs, (uint64_t *)ullp));
786177633Sdfr}
787177633Sdfr
788177633Sdfr
789177633Sdfr/*
790177633Sdfr * XDR longlong_t's
791177633Sdfr */
792177633Sdfrbool_t
793177633Sdfrxdr_longlong_t(XDR *xdrs, longlong_t *llp)
794177633Sdfr{
795177633Sdfr
796177633Sdfr	/*
797177633Sdfr	 * Don't bother open-coding this; it's a fair amount of code.  Just
798177633Sdfr	 * call xdr_int64_t().
799177633Sdfr	 */
800177633Sdfr	return (xdr_int64_t(xdrs, (int64_t *)llp));
801177633Sdfr}
802177633Sdfr
803177633Sdfr
804177633Sdfr/*
805177633Sdfr * XDR u_longlong_t's
806177633Sdfr */
807177633Sdfrbool_t
808177633Sdfrxdr_u_longlong_t(XDR *xdrs, u_longlong_t *ullp)
809177633Sdfr{
810177633Sdfr
811177633Sdfr	/*
812177633Sdfr	 * Don't bother open-coding this; it's a fair amount of code.  Just
813177633Sdfr	 * call xdr_uint64_t().
814177633Sdfr	 */
815177633Sdfr	return (xdr_uint64_t(xdrs, (uint64_t *)ullp));
816177633Sdfr}
817