xref: /xnu-8019.80.24/bsd/nfs/xdr_subs.h (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1 /*
2  * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
29 /*
30  * Copyright (c) 1989, 1993
31  *     The Regents of the University of California.  All rights reserved.
32  *
33  * This code is derived from software contributed to Berkeley by
34  * Rick Macklem at The University of Guelph.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. All advertising materials mentioning features or use of this software
45  *    must display the following acknowledgement:
46  *     This product includes software developed by the University of
47  *     California, Berkeley and its contributors.
48  * 4. Neither the name of the University nor the names of its contributors
49  *    may be used to endorse or promote products derived from this software
50  *    without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62  * SUCH DAMAGE.
63  *
64  *     @(#)xdr_subs.h  8.3 (Berkeley) 3/30/95
65  * FreeBSD-Id: xdr_subs.h,v 1.9 1997/02/22 09:42:53 peter Exp $
66  */
67 
68 #ifndef _NFS_XDR_SUBS_H_
69 #define _NFS_XDR_SUBS_H_
70 
71 #include <sys/appleapiopts.h>
72 
73 #ifdef __APPLE_API_PRIVATE
74 /*
75  * Macros used for conversion to/from xdr representation by nfs...
76  * These use the MACHINE DEPENDENT routines ntohl, htonl
77  * As defined by "XDR: External Data Representation Standard" RFC1014
78  *
79  * To simplify the implementation, we use ntohl/htonl even on big-endian
80  * machines, and count on them being `#define'd away.  Some of these
81  * might be slightly more efficient as quad_t copies on a big-endian,
82  * but we cannot count on their alignment anyway.
83  */
84 
85 #define fxdr_unsigned(t, v)     ((t)ntohl((uint32_t)(v)))
86 #define txdr_unsigned(v)        (htonl((uint32_t)(v)))
87 
88 #define fxdr_hyper(f, t) { \
89 	((uint32_t *)(t))[_QUAD_HIGHWORD] = ntohl(((uint32_t *)(f))[0]); \
90 	((uint32_t *)(t))[_QUAD_LOWWORD] = ntohl(((uint32_t *)(f))[1]); \
91 }
92 #define txdr_hyper(f, t) { \
93 	((uint32_t *)(t))[0] = htonl(((uint32_t *)(f))[_QUAD_HIGHWORD]); \
94 	((uint32_t *)(t))[1] = htonl(((uint32_t *)(f))[_QUAD_LOWWORD]); \
95 }
96 
97 
98 /*
99  * xdrbuf
100  *
101  * generalized functionality for managing the building/dissecting of XDR data
102  */
103 typedef enum xdrbuf_type {
104 	XDRBUF_NONE   = 0,
105 	XDRBUF_BUFFER = 1,
106 } xdrbuf_type;
107 
108 struct xdrbuf {
109 	union {
110 		struct {
111 			char *                  xbb_base;       /* base address of buffer */
112 			size_t                  xbb_size;       /* size of buffer */
113 			size_t                  xbb_len;        /* length of data in buffer */
114 		} xb_buffer;
115 	} xb_u;
116 	char *          xb_ptr;         /* pointer to current position */
117 	size_t          xb_left;        /* bytes remaining in current buffer */
118 	size_t          xb_growsize;    /* bytes to allocate when growing */
119 	xdrbuf_type     xb_type;        /* type of xdr buffer */
120 	uint32_t        xb_flags;       /* XB_* (see below) */
121 };
122 
123 #define XB_CLEANUP      0x0001  /* needs cleanup */
124 
125 #define XDRWORD         4       /* the basic XDR building block is a 4 byte (32 bit) word */
126 #define xdr_rndup(a)    (((a)+3)&(~0x3))        /* round up to XDRWORD size */
127 #define xdr_pad(a)      (xdr_rndup(a) - (a))    /* calculate round up padding */
128 
129 void xb_init(struct xdrbuf *, xdrbuf_type);
130 void xb_init_buffer(struct xdrbuf *, char *, size_t);
131 void xb_cleanup(struct xdrbuf *);
132 void *xb_malloc(size_t);
133 void xb_free(void *);
134 int xb_grow(struct xdrbuf *);
135 void xb_set_cur_buf_len(struct xdrbuf *);
136 char *xb_buffer_base(struct xdrbuf *);
137 int xb_advance(struct xdrbuf *, size_t);
138 size_t xb_offset(struct xdrbuf *);
139 int xb_seek(struct xdrbuf *, size_t);
140 int xb_add_bytes(struct xdrbuf *, const char *, size_t, int);
141 int xb_get_bytes(struct xdrbuf *, char *, uint32_t, int);
142 
143 #ifdef _NFS_XDR_SUBS_FUNCS_
144 
145 /*
146  * basic initialization of xdrbuf structure
147  */
148 void
xb_init(struct xdrbuf * xbp,xdrbuf_type type)149 xb_init(struct xdrbuf *xbp, xdrbuf_type type)
150 {
151 	bzero(xbp, sizeof(*xbp));
152 	xbp->xb_type = type;
153 	xbp->xb_flags |= XB_CLEANUP;
154 }
155 
156 /*
157  * initialize a single-buffer xdrbuf
158  */
159 void
xb_init_buffer(struct xdrbuf * xbp,char * buf,size_t buflen)160 xb_init_buffer(struct xdrbuf *xbp, char *buf, size_t buflen)
161 {
162 	xb_init(xbp, XDRBUF_BUFFER);
163 	xbp->xb_u.xb_buffer.xbb_base = buf;
164 	xbp->xb_u.xb_buffer.xbb_size = buflen;
165 	xbp->xb_u.xb_buffer.xbb_len = buflen;
166 	xbp->xb_growsize = 512;
167 	xbp->xb_ptr = buf;
168 	xbp->xb_left = buflen;
169 	if (buf) { /* when using an existing buffer, xb code should skip cleanup */
170 		xbp->xb_flags &= ~XB_CLEANUP;
171 	}
172 }
173 
174 /*
175  * get the pointer to the single-buffer xdrbuf's buffer
176  */
177 char *
xb_buffer_base(struct xdrbuf * xbp)178 xb_buffer_base(struct xdrbuf *xbp)
179 {
180 	return xbp->xb_u.xb_buffer.xbb_base;
181 }
182 
183 /*
184  * clean up any resources held by an xdrbuf
185  */
186 void
xb_cleanup(struct xdrbuf * xbp)187 xb_cleanup(struct xdrbuf *xbp)
188 {
189 	if (!(xbp->xb_flags & XB_CLEANUP)) {
190 		return;
191 	}
192 	switch (xbp->xb_type) {
193 	case XDRBUF_BUFFER:
194 		if (xbp->xb_u.xb_buffer.xbb_base) {
195 			xb_free(xbp->xb_u.xb_buffer.xbb_base);
196 		}
197 		break;
198 	default:
199 		break;
200 	}
201 	xbp->xb_flags &= ~XB_CLEANUP;
202 }
203 
204 /*
205  * set the length of valid data in the current buffer to
206  * be up to the current location within the buffer
207  */
208 void
xb_set_cur_buf_len(struct xdrbuf * xbp)209 xb_set_cur_buf_len(struct xdrbuf *xbp)
210 {
211 	switch (xbp->xb_type) {
212 	case XDRBUF_BUFFER:
213 		xbp->xb_u.xb_buffer.xbb_len = xbp->xb_ptr - xbp->xb_u.xb_buffer.xbb_base;
214 		break;
215 	default:
216 		break;
217 	}
218 }
219 
220 /*
221  * advance forward through existing data in xdrbuf
222  */
223 int
xb_advance(struct xdrbuf * xbp,size_t len)224 xb_advance(struct xdrbuf *xbp, size_t len)
225 {
226 	size_t tlen;
227 
228 	while (len) {
229 		if (xbp->xb_left <= 0) {
230 			return EBADRPC;
231 		}
232 		tlen = MIN(xbp->xb_left, len);
233 		if (tlen) {
234 			xbp->xb_ptr += tlen;
235 			xbp->xb_left -= tlen;
236 			len -= tlen;
237 		}
238 	}
239 	return 0;
240 }
241 
242 /*
243  * Calculate the current offset in the XDR buffer.
244  */
245 size_t
xb_offset(struct xdrbuf * xbp)246 xb_offset(struct xdrbuf *xbp)
247 {
248 	size_t offset = 0;
249 
250 	switch (xbp->xb_type) {
251 	case XDRBUF_BUFFER:
252 		offset = xbp->xb_ptr - xbp->xb_u.xb_buffer.xbb_base;
253 		break;
254 	default:
255 		break;
256 	}
257 
258 	return offset;
259 }
260 
261 /*
262  * Seek to the given offset in the existing data in the XDR buffer.
263  */
264 int
xb_seek(struct xdrbuf * xbp,size_t offset)265 xb_seek(struct xdrbuf *xbp, size_t offset)
266 {
267 	switch (xbp->xb_type) {
268 	case XDRBUF_BUFFER:
269 		xbp->xb_ptr = xbp->xb_u.xb_buffer.xbb_base + offset;
270 		xbp->xb_left = xbp->xb_u.xb_buffer.xbb_len - offset;
271 		break;
272 	default:
273 		break;
274 	}
275 
276 	return 0;
277 }
278 
279 /*
280  * allocate memory
281  */
282 void *
xb_malloc(size_t size)283 xb_malloc(size_t size)
284 {
285 	void *buf = NULL;
286 
287 #ifdef KERNEL
288 	MALLOC(buf, void *, size, M_TEMP, M_WAITOK);
289 #else
290 	buf = malloc(size);
291 #endif
292 	return buf;
293 }
294 /*
295  * free a chunk of memory allocated with xb_malloc()
296  */
297 void
xb_free(void * buf)298 xb_free(void *buf)
299 {
300 #ifdef KERNEL
301 	FREE(buf, M_TEMP);
302 #else
303 	free(buf);
304 #endif
305 }
306 
307 /*
308  * Increase space available for new data in XDR buffer.
309  */
310 int
xb_grow(struct xdrbuf * xbp)311 xb_grow(struct xdrbuf *xbp)
312 {
313 	char *newbuf, *oldbuf;
314 	size_t newsize, oldsize;
315 
316 	switch (xbp->xb_type) {
317 	case XDRBUF_BUFFER:
318 		oldsize = xbp->xb_u.xb_buffer.xbb_size;
319 		oldbuf = xbp->xb_u.xb_buffer.xbb_base;
320 		newsize = oldsize + xbp->xb_growsize;
321 		if (newsize < oldsize) {
322 			return ENOMEM;
323 		}
324 		newbuf = xb_malloc(newsize);
325 		if (newbuf == NULL) {
326 			return ENOMEM;
327 		}
328 		if (oldbuf != NULL) {
329 			bcopy(oldbuf, newbuf, oldsize);
330 			xb_free(oldbuf);
331 		}
332 		xbp->xb_u.xb_buffer.xbb_base = newbuf;
333 		xbp->xb_u.xb_buffer.xbb_size = newsize;
334 		xbp->xb_ptr = newbuf + oldsize;
335 		xbp->xb_left = xbp->xb_growsize;
336 		break;
337 	default:
338 		break;
339 	}
340 
341 	return 0;
342 }
343 
344 /*
345  * xb_add_bytes()
346  *
347  * Add "count" bytes of opaque data pointed to by "buf" to the given XDR buffer.
348  */
349 int
xb_add_bytes(struct xdrbuf * xbp,const char * buf,size_t count,int nopad)350 xb_add_bytes(struct xdrbuf *xbp, const char *buf, size_t count, int nopad)
351 {
352 	size_t len, tlen;
353 	int error;
354 
355 	len = nopad ? count : xdr_rndup(count);
356 
357 	/* copy in "count" bytes and zero out any pad bytes */
358 	while (len) {
359 		if (xbp->xb_left <= 0) {
360 			/* need more space */
361 			if ((error = xb_grow(xbp))) {
362 				return error;
363 			}
364 			if (xbp->xb_left <= 0) {
365 				return ENOMEM;
366 			}
367 		}
368 		tlen = MIN(xbp->xb_left, len);
369 		if (tlen) {
370 			if (count) {
371 				if (tlen > count) {
372 					tlen = count;
373 				}
374 				bcopy(buf, xbp->xb_ptr, tlen);
375 			} else {
376 				bzero(xbp->xb_ptr, tlen);
377 			}
378 			xbp->xb_ptr += tlen;
379 			xbp->xb_left -= tlen;
380 			len -= tlen;
381 			if (count) {
382 				buf += tlen;
383 				count -= tlen;
384 			}
385 		}
386 	}
387 	return 0;
388 }
389 
390 /*
391  * xb_get_bytes()
392  *
393  * Get "count" bytes of opaque data from the given XDR buffer.
394  */
395 int
xb_get_bytes(struct xdrbuf * xbp,char * buf,uint32_t count,int nopad)396 xb_get_bytes(struct xdrbuf *xbp, char *buf, uint32_t count, int nopad)
397 {
398 	size_t len, tlen;
399 
400 	len = nopad ? count : xdr_rndup(count);
401 
402 	/* copy in "count" bytes and zero out any pad bytes */
403 	while (len) {
404 		if (xbp->xb_left <= 0) {
405 			return ENOMEM;
406 		}
407 		tlen = MIN(xbp->xb_left, len);
408 		if (tlen) {
409 			if (count) {
410 				if (tlen > count) {
411 					tlen = count;
412 				}
413 				bcopy(xbp->xb_ptr, buf, tlen);
414 			}
415 			xbp->xb_ptr += tlen;
416 			xbp->xb_left -= tlen;
417 			len -= tlen;
418 			if (count) {
419 				buf += tlen;
420 				count -= tlen;
421 			}
422 		}
423 	}
424 	return 0;
425 }
426 
427 #endif /* _NFS_XDR_SUBS_FUNCS_ */
428 
429 
430 /*
431  * macros for building XDR data
432  */
433 
434 /* finalize the data that has been added to the buffer */
435 #define xb_build_done(E, XB) \
436 	do { \
437 	        if (E) break; \
438 	        xb_set_cur_buf_len(XB); \
439 	} while (0)
440 
441 /* add a 32-bit value */
442 #define xb_add_32(E, XB, VAL) \
443 	do { \
444 	        uint32_t __tmp; \
445 	        if (E) break; \
446 	        __tmp = txdr_unsigned(VAL); \
447 	        (E) = xb_add_bytes((XB), (void*)&__tmp, XDRWORD, 0); \
448 	} while (0)
449 
450 /* add a 64-bit value */
451 #define xb_add_64(E, XB, VAL) \
452 	do { \
453 	        uint64_t __tmp1, __tmp2; \
454 	        if (E) break; \
455 	        __tmp1 = (VAL); \
456 	        txdr_hyper(&__tmp1, &__tmp2); \
457 	        (E) = xb_add_bytes((XB), (char*)&__tmp2, 2 * XDRWORD, 0); \
458 	} while (0)
459 
460 /* add an array of XDR words */
461 #define xb_add_word_array(E, XB, A, LEN) \
462 	do { \
463 	        uint32_t __i; \
464 	        xb_add_32((E), (XB), (LEN)); \
465 	        for (__i=0; __i < (uint32_t)(LEN); __i++) \
466 	                xb_add_32((E), (XB), (A)[__i]); \
467 	} while (0)
468 #define xb_add_bitmap(E, XB, B, LEN)    xb_add_word_array((E), (XB), (B), (LEN))
469 
470 /* add a file handle */
471 #define xb_add_fh(E, XB, FHP, FHLEN) \
472 	do { \
473 	        xb_add_32((E), (XB), (FHLEN)); \
474 	        if (E) break; \
475 	        (E) = xb_add_bytes((XB), (char*)(FHP), (FHLEN), 0); \
476 	} while (0)
477 
478 /* add a string */
479 #define xb_add_string(E, XB, S, LEN) \
480 	do { \
481 	        xb_add_32((E), (XB), (LEN)); \
482 	        if (E) break; \
483 	        (E) = xb_add_bytes((XB), (const char*)(S), (LEN), 0); \
484 	} while (0)
485 
486 
487 /*
488  * macros for decoding XDR data
489  */
490 
491 /* skip past data in the buffer */
492 #define xb_skip(E, XB, LEN) \
493 	do { \
494 	        if (E) break; \
495 	        (E) = xb_advance((XB), (LEN)); \
496 	} while (0)
497 
498 /* get a 32-bit value */
499 #define xb_get_32(E, XB, LVAL) \
500 	do { \
501 	        uint32_t __tmp; \
502 	        (LVAL) = (typeof((LVAL))) 0; \
503 	        if (E) break; \
504 	        (E) = xb_get_bytes((XB), (char*)&__tmp, XDRWORD, 0); \
505 	        if (E) break; \
506 	        (LVAL) = fxdr_unsigned(uint32_t, __tmp); \
507 	} while (0)
508 
509 /* get a 64-bit value */
510 #define xb_get_64(E, XB, LVAL) \
511 	do { \
512 	        uint64_t __tmp; \
513 	        (LVAL) = 0; \
514 	        if (E) break; \
515 	        (E) = xb_get_bytes((XB), (char*)&__tmp, 2 * XDRWORD, 0); \
516 	        if (E) break; \
517 	        fxdr_hyper(&__tmp, &(LVAL)); \
518 	} while (0)
519 
520 /* get an array of XDR words (of a given expected/maximum length) */
521 #define xb_get_word_array(E, XB, A, LEN) \
522 	do { \
523 	        uint32_t __len = 0, __i; \
524 	        xb_get_32((E), (XB), __len); \
525 	        if (E) break; \
526 	        for (__i=0; __i < MIN(__len, (uint32_t)(LEN)); __i++) \
527 	                xb_get_32((E), (XB), (A)[__i]); \
528 	        if (E) break; \
529 	        for (; __i < __len; __i++) \
530 	                xb_skip((E), (XB), XDRWORD); \
531 	        for (; __i < (uint32_t)(LEN); __i++) \
532 	                (A)[__i] = 0; \
533 	        (LEN) = __len; \
534 	} while (0)
535 #define xb_get_bitmap(E, XB, B, LEN)    xb_get_word_array((E), (XB), (B), (LEN))
536 
537 #endif /* __APPLE_API_PRIVATE */
538 #endif /* _NFS_XDR_SUBS_H_ */
539